<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Casatrick]]></title><description><![CDATA[dev or maker]]></description><link>https://casatrick.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!BYB7!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39d0f855-415b-40e0-81ce-f96e8983295a_1254x1254.png</url><title>Casatrick</title><link>https://casatrick.substack.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 04 Nov 2026 11:55:01 GMT</lastBuildDate><atom:link href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Ffeed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Roswell]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[casatrick@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[casatrick@substack.com]]></itunes:email><itunes:name><![CDATA[Casatrick]]></itunes:name></itunes:owner><itunes:author><![CDATA[Casatrick]]></itunes:author><googleplay:owner><![CDATA[casatrick@substack.com]]></googleplay:owner><googleplay:email><![CDATA[casatrick@substack.com]]></googleplay:email><googleplay:author><![CDATA[Casatrick]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[What It Actually Takes to Run a Polymarket Trading Bot 24/7]]></title><description><![CDATA[A 24/7 trading bot needs more than a strategy. State, execution, reconciliation, risk, monitoring, and recovery all have to keep working.]]></description><link>https://casatrick.substack.com/p/run-polymarket-trading-bot</link><guid isPermaLink="false">https://casatrick.substack.com/p/run-polymarket-trading-bot</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Mon, 05 Oct 2026 07:21:27 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9453b45f-7836-460e-8297-df74347189fb_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A Polymarket trading bot can place orders correctly and still become unreliable after running for a while.</p><p>A WebSocket disconnects.</p><p>A partial fill arrives.</p><p>An event gets missed.</p><p>The process restarts.</p><p>Local state no longer matches the account.</p><p>The strategy continues producing signals anyway.</p><p>That is where running a trading bot 24/7 becomes an infrastructure problem rather than just a trading problem.</p><p>For me, the important part is everything around the strategy:</p><pre><code><code>Market Data
     &#8595;
Strategy
     &#8595;
Risk
     &#8595;
Execution
     &#8595;
Verification
     &#8595;
Reconciliation
     &#8595;
Monitoring
     &#8595;
Recovery</code></code></pre><p>The strategy decides what to trade.</p><p>The rest of the system has to make sure the trading system still knows what is happening.</p><div><hr></div><h2>A running process is not a healthy trading system</h2><p>It is easy to monitor a bot with one metric:</p><pre><code><code>Process = running</code></code></pre><p>That doesn&#8217;t tell you much.</p><p>A process can be running while:</p><ul><li><p>the WebSocket is stale</p></li><li><p>market data is delayed</p></li><li><p>an order is stuck in an unknown state</p></li><li><p>local positions are wrong</p></li><li><p>risk calculations are based on stale state</p></li><li><p>execution hasn&#8217;t been fully verified</p></li><li><p>reconciliation has not completed</p></li></ul><p>A more useful operational model is to give the system explicit states:</p><pre><code><code>HEALTHY
DEGRADED
PAUSED
RECOVERING
FAILED</code></code></pre><p>That gives the bot somewhere to go when something stops looking normal.</p><p>For example:</p><pre><code><code>WebSocket disconnect
        &#8595;
   DEGRADED
        &#8595;
     PAUSED
        &#8595;
  RECOVERING
        &#8595;
    HEALTHY</code></code></pre><p>The important part is that recovery is a state transition, not simply a reconnect call.</p><div><hr></div><h2>WebSocket recovery is more than reconnecting</h2><p>Real-time market data is important for an automated trading system, but being connected does not necessarily mean the system is receiving everything it needs.</p><p>Consider:</p><pre><code><code>Event A
   &#8595;
WebSocket disconnect
   &#8595;
Events B, C, D
   &#8595;
Reconnect</code></code></pre><p>The application knows about A.</p><p>It may not know about B, C, or D.</p><p>When the socket reconnects, the connection is healthy again, but the local trading state may still be incomplete.</p><p>So I treat these as different conditions:</p><pre><code><code>RECONNECTED</code></code></pre><p>and</p><pre><code><code>STATE VERIFIED</code></code></pre><p>The recovery process should be closer to:</p><pre><code><code>WebSocket disconnect
        &#8595;
 Pause trading
        &#8595;
   Reconnect
        &#8595;
Read authoritative state
        &#8595;
Compare local state
        &#8595;
Repair discrepancies
        &#8595;
    Verify
        &#8595;
  Check risk
        &#8595;
    Resume</code></code></pre><p>That distinction becomes especially important when the system can automatically place another order.</p><div><hr></div><h2>Persistent state matters after restarts</h2><p>A 24/7 system will eventually restart.</p><p>It might be an intentional deployment.</p><p>It might be a crash.</p><p>It might be a machine reboot.</p><p>It might be a process supervisor restarting the application.</p><p>None of those should result in:</p><pre><code><code>Process started
      &#8595;
Start trading immediately</code></code></pre><p>The application should first rebuild its understanding of the account.</p><p>A safer startup sequence is:</p><pre><code><code>Application starts
        &#8595;
Load persisted state
        &#8595;
Connect to Polymarket
        &#8595;
Read remote state
        &#8595;
    Compare
        &#8595;
     Repair
        &#8595;
   Verify risk
        &#8595;
  Allow trading</code></code></pre><p>The idea is simple:</p><p><strong>startup is also a recovery event.</strong></p><p>The system should be able to explain what it knows before it begins taking additional risk.</p><div><hr></div><h2>The state you persist is part of the trading system</h2><p>For a continuously running bot, I want persistent records for more than just the last position.</p><p>Useful state includes:</p><pre><code><code>Orders
Fills
Positions
Exposure
Execution status
Risk state
Recovery state
Timestamps
Last known events</code></code></pre><p>That gives the system a history it can use during recovery.</p><p>Without that, debugging often becomes:</p><pre><code><code>"The bot stopped behaving correctly."</code></code></pre><p>with very little information about why.</p><p>With persistent state and structured events, the system can start reconstructing what actually happened.</p><p>That is also important when investigating a position mismatch or an execution that never reached a clean final state.</p><div><hr></div><h2>Execution doesn&#8217;t end at &#8220;filled&#8221;</h2><p>An order being marked as filled is only one part of the execution lifecycle.</p><p>A useful mental model is:</p><pre><code><code>ORDER
  &#8595;
FILL
  &#8595;
TRANSACTION
  &#8595;
CONFIRMATION
  &#8595;
SETTLEMENT
  &#8595;
POSITION</code></code></pre><p>There are different failure modes at every stage.</p><p>For example:</p><pre><code><code>Order accepted
      &#8595;
Fill reported
      &#8595;
Transaction unclear</code></code></pre><p>Or:</p><pre><code><code>Transaction confirmed
      &#8595;
Position state doesn't match</code></code></pre><p>Or:</p><pre><code><code>Partial fill
      &#8595;
Remaining quantity still unresolved</code></code></pre><p>A trading system that only records the initial order response doesn&#8217;t have enough information to reliably answer what happened.</p><p>That is why I separate execution verification from strategy logic.</p><div><hr></div><h2>Partial fills can change everything downstream</h2><p>Imagine the strategy requests:</p><pre><code><code>100 contracts</code></code></pre><p>but the actual execution is:</p><pre><code><code>40 filled
60 remaining</code></code></pre><p>The strategy intended 100.</p><p>The account only gained exposure from 40.</p><p>So the state should flow from actual execution:</p><pre><code><code>Order: 100
   &#8595;
Fill: 40
   &#8595;
Position: +40
   &#8595;
Exposure
   &#8595;
Risk</code></code></pre><p>not:</p><pre><code><code>Order: 100
   &#8595;
Assume Position: +100</code></code></pre><p>That difference matters for position sizing, exposure limits, hedging and the next order.</p><p>Partial fills are not just an execution detail. They affect the state the rest of the trading system relies on.</p><div><hr></div><h2>Position reconciliation closes the loop</h2><p>This is one of the areas I care about most.</p><p>Suppose the local system says:</p><pre><code><code>Position: +100</code></code></pre><p>but the remote account says:</p><pre><code><code>Position: +40</code></code></pre><p>The difference is not a dashboard issue.</p><p>It can affect what the strategy does next.</p><p>If the strategy believes it has only 40 units of exposure, it may decide it has room to add another position.</p><p>The actual account could then end up carrying much more exposure than intended.</p><p>So reconciliation becomes:</p><pre><code><code>Local State
     &#8595;
Remote State
     &#8595;
 Compare
     &#8595;
  Repair
     &#8595;
  Verify</code></code></pre><p>The important word here is <strong>verify</strong>.</p><p>A reconnect is not verification.</p><p>A successful API request is not necessarily verification.</p><p>A process restart is not verification.</p><p>The system needs a point where it can say:</p><pre><code><code>The state is known.
The position is known.
The risk calculation is based on known state.
Trading can resume.</code></code></pre><p>That is the kind of operational layer I&#8217;m building into my Polymarket Trading Control Plane.</p><div><hr></div><h2>What happens when the state is unknown?</h2><p>There are situations where the system cannot immediately establish the correct state.</p><p>For example:</p><pre><code><code>Local position:
+100

Remote position:
UNKNOWN</code></code></pre><p>The dangerous response would be to assume:</p><pre><code><code>Remote = Local</code></code></pre><p>A safer approach is to represent the uncertainty explicitly:</p><pre><code><code>UNKNOWN
   &#8595;
PAUSED
   &#8595;
RETRY
   &#8595;
RECONCILE
   &#8595;
VERIFY</code></code></pre><p>This is one of the more important design principles in automated trading:</p><blockquote><p><strong>Unverified state should not be treated as verified state.</strong></p></blockquote><p>Especially when the next action can create more exposure.</p><div><hr></div><h2>Risk should continue operating even when trading stops</h2><p>Stopping order placement does not mean the rest of the system should stop.</p><p>During an incident or recovery period, the bot should still be able to observe:</p><pre><code><code>Current position
Current exposure
Execution failures
Market-data freshness
Connection health
Reconciliation state
Risk limits</code></code></pre><p>That makes it possible to understand why trading was paused and whether it is safe to resume.</p><p>The trading permission itself can therefore become a controlled output:</p><pre><code><code>Trading = ALLOWED</code></code></pre><p>or:</p><pre><code><code>Trading = BLOCKED</code></code></pre><p>with the reason attached to the decision.</p><p>For example:</p><pre><code><code>Trading blocked

Reason:
POSITION_MISMATCH

Status:
RECONCILIATION_REQUIRED</code></code></pre><p>That is much easier to reason about than a bot that simply stops placing orders without explaining why.</p><div><hr></div><h2>Monitoring should measure behavior, not just uptime</h2><p>A 24/7 bot needs more than a process monitor.</p><p>Useful signals include:</p><pre><code><code>Order latency
Fill ratio
Partial-fill rate
Rejection rate
Unknown execution count
Position mismatches
Reconciliation count
Recovery duration
WebSocket health
Market-data freshness
Risk-limit breaches</code></code></pre><p>These metrics help answer questions such as:</p><pre><code><code>Are executions becoming slower?

Are more orders being rejected?

Are partial fills increasing?

Are state mismatches recurring?

Is recovery taking longer than expected?</code></code></pre><p>Those are much more useful operational questions than:</p><pre><code><code>Is the process alive?</code></code></pre><div><hr></div><h2>Alerts should correspond to actions</h2><p>An alert is more useful when it tells you what actually happened.</p><p>Examples:</p><pre><code><code>STATE_MISMATCH
ORDER_FAILURE
PARTIAL_FILL
MARKET_DATA_STALE
WEBSOCKET_DISCONNECTED
RECONCILIATION_STARTED
RECONCILIATION_COMPLETED
RISK_LIMIT_BREACHED
TRADING_PAUSED
KILL_SWITCH_TRIGGERED</code></code></pre><p>The idea is to connect an observable condition with an operational response.</p><p>For example:</p><pre><code><code>MARKET_DATA_STALE
        &#8595;
Pause affected strategy
        &#8595;
Wait for fresh data
        &#8595;
Verify
        &#8595;
Resume</code></code></pre><p>Or:</p><pre><code><code>STATE_MISMATCH
        &#8595;
Pause
        &#8595;
Reconcile
        &#8595;
Verify
        &#8595;
Risk check
        &#8595;
Resume</code></code></pre><p>This makes the control system much easier to reason about.</p><div><hr></div><h2>Incident history matters</h2><p>When something goes wrong, I want to be able to reconstruct the sequence.</p><p>Something like:</p><pre><code><code>10:42:11  WebSocket disconnected
10:42:11  Trading paused
10:42:14  Reconnect successful
10:42:15  State reconciliation started
10:42:16  Position mismatch detected
10:42:17  Remote position loaded
10:42:18  Local state repaired
10:42:19  Risk verification completed
10:42:20  Trading resumed</code></code></pre><p>That timeline is useful for debugging, but it also becomes useful when trying to improve the system.</p><p>A recurring reconciliation problem might point to an event-handling issue.</p><p>Repeated execution failures might indicate an exchange or network problem.</p><p>Long recovery times might indicate that the recovery path itself needs work.</p><p>Operational history turns isolated incidents into engineering data.</p><div><hr></div><h2>Deployment is part of the trading system</h2><p>Running a trading bot continuously also means dealing with the environment around it.</p><p>That includes:</p><pre><code><code>Process supervision
Configuration
Secrets
Network connectivity
Persistent storage
Logging
Health checks
Resource limits
Restart behavior</code></code></pre><p>A process supervisor can restart a crashed application.</p><p>That is useful.</p><p>But:</p><pre><code><code>automatic restart</code></code></pre><p>does not mean:</p><pre><code><code>safe trading</code></code></pre><p>The application still needs to rebuild state, verify execution, reconcile positions and check risk before allowing new orders.</p><p>The deployment layer and trading layer therefore have to work together.</p><div><hr></div><h2>The architecture I use for this</h2><p>I think of the system as a set of boundaries rather than one large bot:</p><pre><code><code>                   POLYMARKET
                       &#9474;
                       &#9660;
                 Market Data
                       &#9474;
                       &#9660;
                    Strategy
                       &#9474;
                       &#9660;
                      Risk
                       &#9474;
                       &#9660;
                   Execution
                       &#9474;
                       &#9660;
                  Verification
                       &#9474;
                       &#9660;
                Reconciliation
                       &#9474;
             &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
             &#9474;                   &#9474;
             &#9660;                   &#9660;
         Monitoring           Control Plane
             &#9474;                   &#9474;
             &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                       &#9660;
                    Recovery</code></code></pre><p>Each layer has a different responsibility.</p><p>The strategy decides.</p><p>Risk controls what is allowed.</p><p>Execution places the order.</p><p>Verification determines what actually happened.</p><p>Reconciliation establishes whether local and remote state agree.</p><p>Monitoring observes the system.</p><p>The control plane coordinates operational state.</p><p>Recovery brings the system back to a verified condition.</p><p>That separation makes failures easier to reason about.</p><div><hr></div><h2>A practical 24/7 checklist</h2><p>Before allowing automated trading to continue, the system should be able to answer:</p><pre><code><code>[&#10003;] Market data is fresh
[&#10003;] WebSocket is healthy
[&#10003;] Orders are known
[&#10003;] Fills are known
[&#10003;] Positions match
[&#10003;] Exposure is correct
[&#10003;] Risk limits are satisfied
[&#10003;] No unresolved critical mismatch
[&#10003;] Execution state is understood
[&#10003;] Trading can resume</code></code></pre><p>That is what I mean by running a Polymarket bot 24/7.</p><p>It is not simply keeping the binary alive.</p><p>It is maintaining a trustworthy operational state while the system continues to interact with the market.</p><div><hr></div><h2>The broader idea</h2><p>I&#8217;ve been building around this problem with a <strong>Polymarket Trading Control Plane</strong> focused on:</p><pre><code><code>State
Risk
Health
Reconciliation
Alerts
Recovery
Operational control</code></code></pre><p>I also separate execution verification into its own layer so that order state, fills, transactions, confirmations and settlement don&#8217;t get collapsed into one status.</p><p>The repositories are here:</p><p><strong>Polymarket Trading Control Plane</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">https://github.com/casatrickdev/polymarket-trading-control-plane</a></p><p><strong>Polymarket Execution Verifier</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">https://github.com/casatrickdev/polymarket-execution-verifier</a></p><p>The broader trading bot project is here:</p><p><strong>Polymarket Trading Bot</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">https://github.com/casatrickdev/polymarket-trading-bot</a></p><p>Related pieces of the system:</p><p><strong>WebSocket recovery</strong><br><a href="iframe.php?url=https%3A%2F%2Fdev.to%2Fcasatrick%2Fpolymarket-websocket-reconnects-rebuilding-trading-state-safely-47h3">https://dev.to/casatrick/polymarket-websocket-reconnects-rebuilding-trading-state-safely-47h3</a></p><p><strong>Risk controls</strong><br><a href="iframe.php?url=https%3A%2F%2Fdev.to%2Fcasatrick%2Fpolymarket-trading-bot-risk-controls-when-should-a-bot-stop-trading-3m3k">https://dev.to/casatrick/polymarket-trading-bot-risk-controls-when-should-a-bot-stop-trading-3m3k</a></p><p><strong>Incident recovery</strong><br><a href="iframe.php?url=https%3A%2F%2Fdev.to%2Fcasatrick%2Fpolymarket-trading-bot-incident-recovery-how-to-reconstruct-what-happened-1p1n">https://dev.to/casatrick/polymarket-trading-bot-incident-recovery-how-to-reconstruct-what-happened-1p1n</a></p><p><strong>Trading bot architecture</strong><br><a href="iframe.php?url=https%3A%2F%2Fdev.to%2Fcasatrick%2Fbuilding-a-polymarket-trading-bot-architecture-execution-and-risk-management-4gd7">https://dev.to/casatrick/building-a-polymarket-trading-bot-architecture-execution-and-risk-management-4gd7</a></p><div><hr></div><h2>Final takeaway</h2><p>A 24/7 trading bot has to deal with the parts of the system that are easy to ignore when everything is working.</p><p>Connections fail.</p><p>Events are missed.</p><p>Orders partially fill.</p><p>Processes restart.</p><p>State drifts.</p><p>Execution becomes uncertain.</p><p>Risk limits change.</p><p>Recovery takes time.</p><p>The system needs a deliberate way back to a known condition:</p><pre><code><code>Detect
   &#8595;
Pause
   &#8595;
Rebuild state
   &#8595;
Reconcile
   &#8595;
Verify execution
   &#8595;
Check risk
   &#8595;
Resume</code></code></pre><p>That is the infrastructure I think about when I hear &#8220;24/7 trading bot.&#8221;</p><p>The goal isn&#8217;t just to keep the process running.</p><p>It&#8217;s to build a system that fails visibly, recovers deliberately, and knows when its trading state can actually be trusted.</p>]]></content:encoded></item><item><title><![CDATA[Polymarket Trading Bot]]></title><description><![CDATA[polymarket trading bot]]></description><link>https://casatrick.substack.com/p/polymarket-trading-bot</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-trading-bot</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Sat, 03 Oct 2026 15:19:32 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fapi.substack.com%2Ffeed%2Fpodcast%2F218657498%2F8e1f9e3a3d68fd0915253d166c24b12c.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<p></p>]]></content:encoded></item><item><title><![CDATA[Your Polymarket Bot Is Trading. But How Do You Know It’s Actually Healthy?]]></title><description><![CDATA[P&L doesn't tell you everything. Execution latency, fill quality, unresolved state, position mismatches, reconciliation, and recovery can reveal problems earlier.]]></description><link>https://casatrick.substack.com/p/polymarket-trading-bot-execution-analytics</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-trading-bot-execution-analytics</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Sat, 03 Oct 2026 13:04:23 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38e94e1c-5e93-47e0-8171-0ced757759f2_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A Polymarket trading bot can be running normally and still have problems that don&#8217;t show up clearly in the P&amp;L.</p><p>Orders may be taking longer to execute.</p><p>Partial fills may be increasing.</p><p>Rejected orders may be creeping up.</p><p>Some executions may remain unresolved.</p><p>Positions may occasionally drift from what the system expects.</p><p>Recovery may be taking longer than usual.</p><p>The process is still running.</p><p>The strategy is still producing signals.</p><p>The bot may even be making money.</p><p>So from the outside, everything can look fine.</p><p>But the question I care about is:</p><p><strong>What is the execution system actually doing?</strong></p><p>That&#8217;s where execution analytics becomes useful.</p><p>Not as a giant dashboard full of numbers, but as a way to understand whether the trading system is operating normally and when something deserves attention.</p><div><hr></div><h1>P&amp;L doesn&#8217;t tell you enough</h1><p>P&amp;L tells you about the financial result.</p><p>It doesn&#8217;t necessarily tell you about the health of the execution layer.</p><p>Imagine:</p><pre><code><code>P&amp;L          &#8594; positive
Bot status   &#8594; running
Orders       &#8594; active</code></code></pre><p>That sounds good.</p><p>But underneath:</p><pre><code><code>Fill latency        &#8593;
Partial fills       &#8593;
Rejected orders     &#8593;
Unknown executions  &#8593;
Recovery time       &#8593;</code></code></pre><p>Now the system is telling a different story.</p><p>The problem may not have turned into a visible loss yet.</p><p>That doesn&#8217;t mean it isn&#8217;t important.</p><div><hr></div><h1>What I actually want to measure</h1><p>For an automated trading system, I want a small set of metrics that correspond to real operational questions.</p><p>Things like:</p><pre><code><code>Order latency
Fill latency
Fill ratio
Partial-fill rate
Rejection rate
Execution failures
Unknown execution count
Unknown execution duration
Position mismatches
Reconciliation duration
Recovery duration</code></code></pre><p>The exact numbers will vary between systems.</p><p>What matters more is what the metrics allow you to see.</p><p>For example:</p><blockquote><p>Are orders becoming slower?</p><p>Are fills becoming less complete?</p><p>Are unresolved executions accumulating?</p><p>Is the system disagreeing with account state more often?</p><p>Is recovery taking longer?</p></blockquote><p>Those are questions a client can actually use.</p><div><hr></div><h1>Start with the order</h1><p>The first part of the lifecycle is simple:</p><pre><code><code>Strategy Decision
      &#8595;
Order Created
      &#8595;
Order Submitted</code></code></pre><p>This gives you an opportunity to measure the time spent getting from a decision to an actual submitted order.</p><p>You can then look at the distribution instead of only one average.</p><p>For example:</p><pre><code><code>p50
p95
p99</code></code></pre><p>Why does that matter?</p><p>Because a system can have a perfectly normal median while occasionally producing very slow executions.</p><p>Those slow cases may be more interesting than the average.</p><div><hr></div><h1>Then look at the fill</h1><p>Order submission is only one point in the lifecycle.</p><p>The next part is:</p><pre><code><code>Order Submitted
      &#8595;
Fill Observed</code></code></pre><p>Now you can measure fill latency.</p><p>For example:</p><pre><code><code>Order A &#8594; 150 ms
Order B &#8594; 170 ms
Order C &#8594; 3.5 s</code></code></pre><p>One slow order doesn&#8217;t automatically mean something is broken.</p><p>But if the system normally looks like:</p><pre><code><code>150&#8211;200 ms</code></code></pre><p>and suddenly looks like:</p><pre><code><code>1&#8211;4 s</code></code></pre><p>that&#8217;s worth investigating.</p><p>The metric isn&#8217;t the answer.</p><p>It&#8217;s the signal that tells you where to look.</p><div><hr></div><h1>Fill ratio tells a different story</h1><p>Suppose the bot requests:</p><pre><code><code>100</code></code></pre><p>and actually receives:</p><pre><code><code>70</code></code></pre><p>Then:</p><pre><code><code>Requested: 100
Matched:    70</code></code></pre><p>The system should preserve that difference.</p><p>A fill ratio tells you how much of the requested quantity actually executed.</p><p>Over time, that lets you see whether execution behavior is changing.</p><p>For example:</p><pre><code><code>Earlier period: 89%
Current period: 68%</code></code></pre><p>That doesn&#8217;t automatically tell you why.</p><p>But it tells you something changed.</p><p>That can lead to questions about market conditions, execution configuration, inventory, or strategy behavior.</p><div><hr></div><h1>Partial fills create downstream work</h1><p>Partial fills are especially interesting because they don&#8217;t always stop at the execution layer.</p><p>Suppose:</p><pre><code><code>Requested: 100
Filled:     40
Remaining:  60</code></code></pre><p>Now the system needs to deal with:</p><pre><code><code>remaining quantity
position update
exposure update
risk
possible reconciliation</code></code></pre><p>That&#8217;s why I wrote earlier about <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-partial-fills-trading-bot">Polymarket partial fills</a></strong>.</p><p>A partial fill isn&#8217;t just an execution statistic.</p><p>It can change the state that everything else in the trading system depends on.</p><p>So one useful thing to measure is not just the number of partial fills, but what those partial fills cause afterward.</p><div><hr></div><h1>Rejections are another signal</h1><p>A rejection rate is straightforward:</p><pre><code><code>rejected orders
----------------
submitted orders</code></code></pre><p>The important part is the trend.</p><p>For example:</p><pre><code><code>Monday     0.8%
Tuesday    0.9%
Wednesday  1.0%
Thursday   3.9%</code></code></pre><p>I wouldn&#8217;t look at that and immediately conclude that something is broken.</p><p>I&#8217;d investigate.</p><p>Break the data down by:</p><pre><code><code>market
strategy
side
time
reason</code></code></pre><p>The goal is to move from:</p><blockquote><p>&#8220;There were more rejections.&#8221;</p></blockquote><p>to:</p><blockquote><p>&#8220;Rejections increased in this part of the execution path.&#8221;</p></blockquote><p>That&#8217;s much more actionable.</p><div><hr></div><h1>Unknown execution state deserves its own metric</h1><p>This is one of the things I&#8217;m particularly interested in.</p><p>A trade can reach an intermediate state where the system knows that something happened, but doesn&#8217;t yet have enough information to consider the execution complete.</p><p>For example:</p><pre><code><code>FILLED
   &#8595;
TX_PENDING</code></code></pre><p>Or:</p><pre><code><code>Execution = UNKNOWN</code></code></pre><p>Instead of hiding that state, measure it.</p><p>For example:</p><pre><code><code>Unknown executions: 3
Oldest unresolved: 18.4 seconds</code></code></pre><p>Now you know both:</p><pre><code><code>how many</code></code></pre><p>and:</p><pre><code><code>how long</code></code></pre><p>The second number can be more useful than the first.</p><p>Three unknown executions for a few hundred milliseconds is one situation.</p><p>Three unknown executions that have been unresolved for minutes is another.</p><p>This is one of the reasons I&#8217;ve been building the <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">Polymarket Execution Verifier</a></strong> as a separate layer.</p><div><hr></div><h1>Execution isn&#8217;t the end of the state problem</h1><p>Suppose the execution itself is verified.</p><p>You can still have:</p><pre><code><code>Expected Position: 100
Observed Position:  40</code></code></pre><p>Now the execution may be fine.</p><p>The position is not.</p><p>That is where <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-position-reconciliation">Polymarket position reconciliation</a></strong> comes in.</p><p>For analytics, I&#8217;d want to know:</p><pre><code><code>How often does this happen?

How large are the differences?

How long do they last?

How quickly are they resolved?</code></code></pre><p>That&#8217;s much more useful than simply showing:</p><pre><code><code>Position mismatch: YES</code></code></pre><div><hr></div><h1>Recovery time tells you something about the system</h1><p>A system can recover from a problem in two seconds or two minutes.</p><p>Both may end with:</p><pre><code><code>System = Healthy</code></code></pre><p>But they&#8217;re not operationally identical.</p><p>A recovery flow can look like:</p><pre><code><code>Disconnect
   &#8595;
Pause
   &#8595;
Reconnect
   &#8595;
Reconcile
   &#8595;
Verify
   &#8595;
Risk Check
   &#8595;
Resume</code></code></pre><p>Now measure:</p><pre><code><code>Recovery Started
        &#8595;
Recovery Completed</code></code></pre><p>You can also break it down further:</p><pre><code><code>disconnect &#8594; reconnect
reconnect &#8594; reconcile
reconcile &#8594; verify
verify &#8594; risk check
risk check &#8594; resume</code></code></pre><p>That tells you where recovery is spending its time.</p><p>It also connects naturally to the <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fi-switched-my-polymarket-bot-to-websocket">Polymarket WebSocket recovery</a></strong> work I&#8217;ve been doing.</p><div><hr></div><h1>Metrics should come from events</h1><p>This is the architectural part I care about most.</p><p>Rather than putting random counters throughout the codebase, make important state transitions observable.</p><p>For example:</p><pre><code><code>ORDER_SUBMITTED
FILL_OBSERVED
TX_PENDING
TX_CONFIRMED
POSITION_VERIFIED
POSITION_MISMATCH
RECONCILIATION_STARTED
RECONCILIATION_COMPLETED
RECOVERY_STARTED
RECOVERY_COMPLETED</code></code></pre><p>Each event can carry information such as:</p><pre><code><code>execution_id
order_id
trade_id
market_id
timestamp
state
reason
quantity</code></code></pre><p>From those events, you can derive metrics.</p><p>For example:</p><pre><code><code>ORDER_SUBMITTED
        &#8595;
FILL_OBSERVED

= Fill Latency</code></code></pre><p>and:</p><pre><code><code>RECOVERY_STARTED
        &#8595;
RECOVERY_COMPLETED

= Recovery Duration</code></code></pre><p>The advantage is that the same event history can support:</p><pre><code><code>metrics
logs
alerts
incident analysis
reconciliation</code></code></pre><p>You aren&#8217;t building five separate representations of the same system.</p><div><hr></div><h1>I don&#8217;t want a dashboard full of vanity metrics</h1><p>It&#8217;s easy to create a dashboard that looks impressive:</p><pre><code><code>24h Volume
Number of Trades
P&amp;L
Orders
Fills</code></code></pre><p>But those numbers don&#8217;t necessarily tell an operator whether the system is healthy.</p><p>I&#8217;d rather have:</p><pre><code><code>Fill Latency
Partial-Fill Rate
Rejection Rate
Unknown Execution Duration
Position Mismatch Count
Reconciliation Duration
Recovery Duration</code></code></pre><p>because each one corresponds to an actual operational question.</p><p>The goal is not more metrics.</p><p>It&#8217;s <strong>more useful information</strong>.</p><div><hr></div><h1>Metrics should feed the control plane</h1><p>The interesting next step is connecting analytics to operational state.</p><p>For example:</p><pre><code><code>Fill latency &#8593;
Rejections &#8593;
Unknown duration &#8593;
        &#8595;
Execution Health
DEGRADED</code></code></pre><p>Or:</p><pre><code><code>Position mismatches &#8593;
Reconciliation time &#8593;
        &#8595;
State Health
DEGRADED</code></code></pre><p>Or:</p><pre><code><code>Recovery duration &#8593;
        &#8595;
System Health
DEGRADED</code></code></pre><p>Then the control plane can decide whether to:</p><pre><code><code>continue
alert
pause
reconcile
recover</code></code></pre><p>The analytics layer doesn&#8217;t have to make the final decision.</p><p>It gives the control plane reliable signals to work with.</p><p>That&#8217;s the direction I&#8217;m taking with the <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">Polymarket Trading Control Plane</a></strong>.</p><div><hr></div><h1>What a client should actually be able to see</h1><p>From a client&#8217;s point of view, I don&#8217;t think the important question is:</p><blockquote><p>&#8220;How many transactions did the bot send?&#8221;</p></blockquote><p>It is more like:</p><blockquote><p>&#8220;Is the system operating normally?&#8221;</p></blockquote><p>A useful operational view might look like:</p><pre><code><code>EXECUTION

Orders                  1,248
Fill Ratio                 86%
Partial Fills               94
Rejected Orders              11
Unknown Executions            3

p50 Fill Latency           180 ms
p95 Fill Latency           620 ms

Position Mismatches           2
Active Recoveries             0</code></code></pre><p>And then the operator should be able to drill into a problem.</p><p>For example:</p><pre><code><code>Position Mismatches: 2
       &#8595;
Market
       &#8595;
Execution
       &#8595;
Event history
       &#8595;
Reconciliation</code></code></pre><p>That is much more useful than another chart showing a daily volume number.</p><div><hr></div><h1>The real value is knowing what changed</h1><p>Suppose the bot worked normally for two weeks.</p><p>Then suddenly:</p><pre><code><code>fill latency      &#8593;
partial fills     &#8593;
unknown states    &#8593;
recovery time     &#8593;</code></code></pre><p>The important observation is not any single metric.</p><p>It&#8217;s the fact that several parts of the execution system changed together.</p><p>That&#8217;s when analytics becomes a form of early warning.</p><p>The system is telling you:</p><blockquote><p>Something about the way we&#8217;re operating is different.</p></blockquote><p>You can then investigate before the problem turns into something more serious.</p><div><hr></div><h1>Don&#8217;t start with fifty metrics</h1><p>I wouldn&#8217;t.</p><p>Start with a small set:</p><pre><code><code>Order latency
Fill latency
Fill ratio
Partial-fill rate
Rejection rate
Unknown execution count
Unknown execution duration
Position mismatch count
Reconciliation duration
Recovery duration</code></code></pre><p>Then add another metric when there is a real question it can answer.</p><p>That keeps the monitoring layer understandable.</p><div><hr></div><h1>The broader system I&#8217;m building</h1><p>This is how the pieces fit together for me:</p><pre><code><code>Polymarket Trading Bot
        &#8595;
Execution
        &#8595;
Execution Verifier
        &#8595;
Position Reconciliation
        &#8595;
Risk Controls
        &#8595;
Trading Control Plane
        &#8595;
Execution Analytics</code></code></pre><p>Each layer has a different responsibility.</p><p>The bot decides what to do.</p><p>Execution carries out the intent.</p><p>The verifier determines what happened.</p><p>Reconciliation checks whether state matches reality.</p><p>Risk decides whether the resulting conditions are acceptable.</p><p>The Control Plane coordinates health, recovery, and trading permissions.</p><p>Analytics tells you how those systems are behaving over time.</p><div><hr></div><h1>Final thought</h1><p>A trading bot being profitable doesn&#8217;t necessarily mean the trading system is healthy.</p><p>You can have positive P&amp;L while:</p><pre><code><code>latency is increasing
fills are getting worse
rejections are increasing
execution stays unresolved longer
positions drift
recovery gets slower</code></code></pre><p>That&#8217;s why I want execution analytics to be part of the infrastructure rather than an afterthought.</p><p>The model is:</p><pre><code><code>Execution
   &#8595;
Events
   &#8595;
Metrics
   &#8595;
Health
   &#8595;
Risk / Control
   &#8595;
Action</code></code></pre><p>The goal isn&#8217;t a prettier dashboard.</p><p>It&#8217;s being able to answer:</p><blockquote><p><strong>What is happening to the trading system right now, and does anything need to change?</strong></p></blockquote><p>That&#8217;s the level of observability I want around an automated Polymarket trading system.</p>]]></content:encoded></item><item><title><![CDATA[Your Polymarket Bot Restarted. But Does It Know What Happened?]]></title><description><![CDATA[Restarting a trading bot is easy. Reconstructing the state it lost before you let it trade again is the harder problem.]]></description><link>https://casatrick.substack.com/p/polymarket-trading-bot-incident-recovery</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-trading-bot-incident-recovery</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Fri, 02 Oct 2026 06:51:34 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c505885-ee6a-41b0-876a-1acc21006af1_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A Polymarket trading bot stops.</p><p>You restart the process.</p><p>The logs look normal again.</p><p>The WebSocket connects.</p><p>The strategy starts running.</p><p>It can feel like the incident is over.</p><p>But there is a more important question:</p><p><strong>Does the system actually know what happened before it restarted?</strong></p><p>That is the part I&#8217;m increasingly interested in with automated trading systems.</p><p>A process restarting successfully doesn&#8217;t mean its trading state is correct.</p><p>You can still have:</p><pre><code><code>unknown orders
missing fills
wrong positions
stale exposure
unverified execution
incomplete recovery
</code></code></pre><p>And if the system doesn&#8217;t know which of those conditions exists, allowing it to trade again can make the original problem worse.</p><p>That&#8217;s why I&#8217;ve been treating <strong>incident recovery as a state-reconstruction problem</strong>, not a restart problem.</p><div><hr></div><h1>The easy version of recovery</h1><p>The simplest architecture is:</p><pre><code><code>Bot crashes
   &#8595;
Restart
   &#8595;
Connect
   &#8595;
Trade again
</code></code></pre><p>It&#8217;s attractive because it is simple.</p><p>It&#8217;s also making a large assumption:</p><blockquote><p>Everything the bot knew before the failure was correct, and nothing important happened while it was down.</p></blockquote><p>Real systems don&#8217;t give you that guarantee.</p><p>A more useful recovery flow is:</p><pre><code><code>Incident
   &#8595;
Pause Trading
   &#8595;
Reconstruct State
   &#8595;
Reconcile
   &#8595;
Verify
   &#8595;
Check Risk
   &#8595;
Resume
</code></code></pre><p>The restart is just one step in that process.</p><div><hr></div><h1>Start with the last known good state</h1><p>When something goes wrong, the first useful piece of information isn&#8217;t the current state.</p><p>It&#8217;s the <strong>last state you actually trusted</strong>.</p><p>For example:</p><pre><code><code>Last verified state
        &#8595;
       gap
        &#8595;
Current state
</code></code></pre><p>The system needs to establish what happened inside that gap.</p><p>That can mean looking at:</p><pre><code><code>orders
fills
execution state
positions
market events
connection events
risk state
</code></code></pre><p>A recovery system should be able to answer:</p><blockquote><p>What did the bot know before the incident?</p><p>What changed around the incident?</p><p>What is actually true now?</p></blockquote><p>Without those answers, recovery becomes guesswork.</p><div><hr></div><h1>The bot can be running while the trading state is broken</h1><p>This is similar to the issue I wrote about in <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fi-switched-my-polymarket-bot-to-websocket">Polymarket WebSocket recovery</a></strong>.</p><p>Imagine:</p><pre><code><code>Process:
RUNNING

WebSocket:
CONNECTED

Strategy:
ACTIVE
</code></code></pre><p>Everything looks fine from a process-monitoring perspective.</p><p>Then:</p><pre><code><code>Position:
UNVERIFIED
</code></code></pre><p>Now the situation is very different.</p><p>The software is alive.</p><p>The trading system isn&#8217;t necessarily trustworthy.</p><p>That distinction matters because automated systems don&#8217;t care whether a process is &#8220;up&#8221; if the state it is acting on is wrong.</p><div><hr></div><h1>What actually happened before the failure?</h1><p>Imagine the bot was handling an order.</p><pre><code><code>Order submitted
      &#8595;
Fill observed
      &#8595;
WebSocket disconnect
      &#8595;
Process stops
</code></code></pre><p>When the process comes back, it may know about the order.</p><p>It may not know everything that happened afterward.</p><p>The execution could be:</p><pre><code><code>FILLED
TX_PENDING
CONFIRMED
SETTLED
</code></code></pre><p>or it could still be uncertain.</p><p>That&#8217;s why I&#8217;ve been building the separate <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">Polymarket Execution Verifier</a></strong>.</p><p>Its job is to make execution state explicit instead of treating every fill as the final answer.</p><div><hr></div><h1>Partial fills make recovery even harder</h1><p>Suppose the strategy requested:</p><pre><code><code>100
</code></code></pre><p>and the system had observed:</p><pre><code><code>40 filled
60 remaining
</code></code></pre><p>Then the application stops.</p><p>When it starts again, the remaining 60 could be:</p><pre><code><code>still open
filled
cancelled
unknown
</code></code></pre><p>The system can&#8217;t just assume the previous snapshot is still correct.</p><p>That&#8217;s closely related to the <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-partial-fills-trading-bot">partial-fill problem</a></strong> I wrote about earlier.</p><p>The important distinction is always:</p><pre><code><code>Requested quantity
        &#8800;
Executed quantity
        &#8800;
Current position
</code></code></pre><p>Those values need to be reconstructed independently.</p><div><hr></div><h1>Then there is the position</h1><p>Suppose the recovered local state says:</p><pre><code><code>Position:
+100
</code></code></pre><p>The current account state says:</p><pre><code><code>Position:
+40
</code></code></pre><p>Now the system has an incident.</p><p>It isn&#8217;t enough to say:</p><blockquote><p>&#8220;The database says +100.&#8221;</p></blockquote><p>And it isn&#8217;t enough to blindly overwrite it with +40 without understanding the difference.</p><p>You need to establish why they differ.</p><p>Possibilities include:</p><pre><code><code>partial fill
missed event
unexpected order state
stale local state
restart during execution</code></code></pre><p>This is the same reason I treat <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-position-reconciliation">Polymarket position reconciliation</a></strong> as its own layer.</p><p>The goal is to move from:</p><pre><code><code>UNKNOWN / INCONSISTENT</code></code></pre><p>to:</p><pre><code><code>VERIFIED</code></code></pre><p>before normal trading resumes.</p><div><hr></div><h1>Reconciliation is part of recovery</h1><p>I think these concepts are related, but not identical.</p><p>Reconciliation asks:</p><blockquote><p>Does local state match external state?</p></blockquote><pre><code><code>Local
  &#8595;
Remote
  &#8595;
Compare
  &#8595;
Repair</code></code></pre><p>Incident recovery asks:</p><blockquote><p>What happened, what state became uncertain, and what has to be verified before the system can safely operate again?</p></blockquote><pre><code><code>Incident
   &#8595;
Reconstruct
   &#8595;
Reconcile
   &#8595;
Verify
   &#8595;
Recover</code></code></pre><p>Reconciliation is therefore one of the important stages of recovery.</p><div><hr></div><h1>The incident needs a timeline</h1><p>One thing I want from a trading system is the ability to reconstruct the sequence.</p><p>For example:</p><pre><code><code>10:41:08  Order submitted
10:41:09  Fill observed
10:41:10  WebSocket disconnected
10:41:11  Execution became uncertain
10:41:18  Process stopped
10:42:03  Process restarted
10:42:04  Trading paused
10:42:05  Reconciliation started
10:42:06  Position mismatch found
10:42:07  Remote state fetched
10:42:08  Position verified
10:42:09  Risk checks passed
10:42:10  Trading resumed</code></code></pre><p>That gives an operator a story.</p><p>Without it, the incident might only look like:</p><pre><code><code>Bot stopped
Bot restarted</code></code></pre><p>That&#8217;s not enough.</p><div><hr></div><h1>Why event history matters</h1><p>A trading system is a sequence of state changes.</p><p>So when the system fails, you need enough history to reconstruct those changes.</p><p>For example:</p><pre><code><code>Order event
   &#8595;
Fill event
   &#8595;
Connection event
   &#8595;
Recovery event
   &#8595;
Reconciliation</code></code></pre><p>That history helps answer:</p><blockquote><p>Did the bot miss an event?</p><p>Did a partial fill happen before the failure?</p><p>Was the position already inconsistent?</p><p>Did the recovery process actually resolve the mismatch?</p></blockquote><p>This is why observability is not only about logs.</p><p>It&#8217;s about retaining enough structured state to explain how the system got where it is.</p><div><hr></div><h1>Don&#8217;t confuse reconnect with recovery</h1><p>This is one of the biggest distinctions in the system.</p><p>A reconnect means:</p><pre><code><code>I can receive data again.</code></code></pre><p>Recovery means:</p><pre><code><code>I have re-established a trustworthy trading state.</code></code></pre><p>Those are different.</p><p>The safer sequence is:</p><pre><code><code>Disconnect
   &#8595;
Pause
   &#8595;
Reconnect
   &#8595;
Rebuild
   &#8595;
Reconcile
   &#8595;
Verify
   &#8595;
Check Risk
   &#8595;
Resume</code></code></pre><p>That&#8217;s why a WebSocket reconnect should not automatically flip the system back into normal trading.</p><div><hr></div><h1>Recovery should start by freezing new risk</h1><p>When state becomes uncertain, I don&#8217;t want the system adding more exposure while it is trying to understand the existing exposure.</p><p>So:</p><pre><code><code>Incident
   &#8595;
Trading Paused</code></code></pre><p>The system can still:</p><pre><code><code>inspect
reconcile
verify
recover</code></code></pre><p>But it isn&#8217;t blindly creating more positions during the investigation.</p><p>This is where recovery connects directly with the risk layer.</p><div><hr></div><h1>Risk needs the recovered state</h1><p>Suppose the system thought it had:</p><pre><code><code>Position = +40</code></code></pre><p>but after reconciliation it discovers:</p><pre><code><code>Position = +100</code></code></pre><p>The risk calculation changes.</p><p>The available capacity changes.</p><p>The next order may no longer be acceptable.</p><p>That&#8217;s why recovery shouldn&#8217;t end at:</p><pre><code><code>Position fixed</code></code></pre><p>It should continue:</p><pre><code><code>Position verified
      &#8595;
Exposure recalculated
      &#8595;
Risk checked</code></code></pre><p>Only then can the system decide whether trading can resume.</p><div><hr></div><h1>What happens when you can&#8217;t verify the state?</h1><p>Sometimes there won&#8217;t be an immediate answer.</p><p>For example:</p><pre><code><code>Local position:
+100

Remote position:
UNKNOWN</code></code></pre><p>Or:</p><pre><code><code>Execution:
UNKNOWN</code></code></pre><p>The wrong response is to manufacture certainty:</p><pre><code><code>UNKNOWN &#8594; HEALTHY</code></code></pre><p>The better response is:</p><pre><code><code>UNKNOWN
   &#8595;
PAUSED
   &#8595;
RETRY / RECONCILE</code></code></pre><p>Unknown is a valid system state.</p><p>The system needs to be comfortable saying:</p><blockquote><p>&#8220;I don&#8217;t know yet.&#8221;</p></blockquote><p>That is much safer than pretending it knows.</p><div><hr></div><h1>Recovery should be repeatable</h1><p>Another property I care about is idempotency.</p><p>Suppose recovery is triggered twice.</p><p>You don&#8217;t want:</p><pre><code><code>Recovery 1
Recovery 2</code></code></pre><p>to produce conflicting state.</p><p>The operations should be safe to repeat:</p><pre><code><code>PAUSE
PAUSE</code></code></pre><p>still means:</p><pre><code><code>PAUSED</code></code></pre><p>and:</p><pre><code><code>RECONCILE
RECONCILE</code></code></pre><p>should not double-count fills or create duplicate state.</p><p>This matters because the recovery system itself can have failures.</p><div><hr></div><h1>The control plane is where this comes together</h1><p>This is the problem I&#8217;m solving with the <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">Polymarket Trading Control Plane</a></strong>.</p><p>The control plane sits above the trading components and coordinates:</p><pre><code><code>health
risk
execution state
positions
reconciliation
recovery
alerts
trading permission</code></code></pre><p>So the system can move through something like:</p><pre><code><code>HEALTHY
   &#8595;
DEGRADED
   &#8595;
PAUSED
   &#8595;
RECOVERING
   &#8595;
HEALTHY</code></code></pre><p>That makes recovery visible.</p><p>The system isn&#8217;t simply &#8220;online&#8221; or &#8220;offline.&#8221;</p><p>It knows that it is recovering.</p><div><hr></div><h1>The control plane should know why trading is paused</h1><p>A useful system state isn&#8217;t just:</p><pre><code><code>Trading:
PAUSED</code></code></pre><p>It should know why.</p><p>For example:</p><pre><code><code>Trading:
PAUSED

Reason:
POSITION_MISMATCH

Expected:
100

Observed:
40</code></code></pre><p>Or:</p><pre><code><code>Trading:
PAUSED

Reason:
EXECUTION_UNKNOWN</code></code></pre><p>Or:</p><pre><code><code>Trading:
PAUSED

Reason:
MARKET_DATA_STALE</code></code></pre><p>That information can then drive:</p><pre><code><code>alerts
dashboard
recovery
operator actions</code></code></pre><p>This is what turns operational state into something the rest of the system can actually use.</p><div><hr></div><h1>Recovery is also about learning from incidents</h1><p>Once an incident has been reconstructed, you have something useful beyond recovery.</p><p>You can look at:</p><pre><code><code>frequency
duration
trigger
affected execution
affected market
state mismatch
recovery path</code></code></pre><p>Over time, patterns start to appear.</p><p>Maybe most incidents come from:</p><pre><code><code>WebSocket gaps</code></code></pre><p>Maybe a particular execution state repeatedly becomes uncertain.</p><p>Maybe recovery is taking too long because reconciliation is slow.</p><p>The incident history becomes a source of engineering information.</p><div><hr></div><h1>What I want from a recovered system</h1><p>Before a bot resumes, I want the system to be able to answer:</p><pre><code><code>What happened?</code></code></pre><pre><code><code>What did the bot believe</code></code></pre><pre><code><code>What does the account actually show?</code></code></pre><pre><code><code>What was reconciled?</code></code></pre><pre><code><code>What remains uncertain?</code></code></pre><pre><code><code>What is the current exposure?</code></code></pre><pre><code><code>Did the risk checks pass?</code></code></pre><p>And finally:</p><pre><code><code>Can trading resume?</code></code></pre><p>That&#8217;s a very different definition of recovery from:</p><blockquote><p>&#8220;The process started successfully.&#8221;</p></blockquote><div><hr></div><h1>The recovery model</h1><p>The model I&#8217;m working with is:</p><pre><code><code>INCIDENT
   &#8595;
PAUSE
   &#8595;
RECONSTRUCT
   &#8595;
RECONCILE
   &#8595;
VERIFY
   &#8595;
CHECK RISK
   &#8595;
RESUME</code></code></pre><p>Every step exists for a reason.</p><p><strong>Pause</strong> prevents additional risk while state is uncertain.</p><p><strong>Reconstruct</strong> establishes the history around the incident.</p><p><strong>Reconcile</strong> compares local state with external state.</p><p><strong>Verify</strong> establishes that the resulting execution and position are trustworthy.</p><p><strong>Check Risk</strong> determines whether the recovered state is still within policy.</p><p><strong>Resume</strong> only happens after those conditions are satisfied.</p><div><hr></div><h1>Final thought</h1><p>I don&#8217;t think the hard part of an automated trading system is keeping the process alive.</p><p>The harder part is recovering from the moment when the system no longer knows exactly what happened.</p><p>A bot can restart.</p><p>A WebSocket can reconnect.</p><p>The process can look perfectly healthy.</p><p>And the trading state can still be wrong.</p><p>That&#8217;s why I&#8217;m treating incident recovery as a separate part of the Polymarket infrastructure:</p><pre><code><code>Incident
   &#8595;
Pause
   &#8595;
Reconstruct
   &#8595;
Reconcile
   &#8595;
Verify
   &#8595;
Risk Check
   &#8595;
Resume</code></code></pre><p>The goal isn&#8217;t just to get the bot running again.</p><p>It&#8217;s to get it back to a state where it <strong>knows what happened, knows what is true now, and has enough verified information to continue trading safely</strong>.</p>]]></content:encoded></item><item><title><![CDATA[Your Polymarket Bot Has a Signal. That Doesn’t Mean It Should Trade.]]></title><description><![CDATA[A good trading system needs to know not only when to trade, but when to stop: stale data, position mismatch, execution uncertainty, exposure, risk limits, and recovery.]]></description><link>https://casatrick.substack.com/p/polymarket-trading-bot-risk-controls</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-trading-bot-risk-controls</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Thu, 01 Oct 2026 14:46:18 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb52feafc-8806-4215-a04c-58dd34088d81_1983x793.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A trading bot can have a perfectly valid signal and still be in a state where placing another order is a bad idea.</p><p>That is one of the things I think gets overlooked when people talk about automated Polymarket trading.</p><p>The usual question is:</p><blockquote><p>&#8220;When should the bot buy?&#8221;</p></blockquote><p>But once the system is running continuously, another question becomes just as important:</p><blockquote><p><strong>&#8220;When should the bot refuse to trade?&#8221;</strong></p></blockquote><p>That is a risk-control problem.</p><p>And it is much bigger than putting a maximum position size somewhere in the code.</p><div><hr></div><h2>A signal is only the beginning</h2><p>A simple trading loop looks like:</p><pre><code><code>Market Data
    &#8595;
Strategy
    &#8595;
Order
    &#8595;
Execution</code></code></pre><p>That works as a conceptual model.</p><p>A production system needs more checks in between.</p><p>Something closer to:</p><pre><code><code>Market Data
    &#8595;
Strategy
    &#8595;
Risk Check
    &#8595;
Execution
    &#8595;
Verification
    &#8595;
Reconciliation
    &#8595;
Risk Recheck
    &#8595;
Continue / Pause</code></code></pre><p>The strategy can say:</p><blockquote><p>&#8220;I want to buy.&#8221;</p></blockquote><p>The system still needs to decide:</p><blockquote><p>&#8220;Are we actually allowed to buy?&#8221;</p></blockquote><p>Those are different decisions.</p><div><hr></div><h1>What can make a good trade unsafe?</h1><p>Consider a normal situation.</p><p>The strategy generates a BUY signal.</p><p>The market data looks fine.</p><p>The order looks reasonable.</p><p>But the system discovers:</p><pre><code><code>Current position is already near its limit.</code></code></pre><p>Or:</p><pre><code><code>Market data has gone stale.</code></code></pre><p>Or:</p><pre><code><code>The previous execution is still unverified.</code></code></pre><p>Or:</p><pre><code><code>The local position does not match the external position.</code></code></pre><p>Or:</p><pre><code><code>Portfolio exposure is already too high.</code></code></pre><p>Or:</p><pre><code><code>The system is still recovering from a connection failure.</code></code></pre><p>The signal hasn&#8217;t changed.</p><p>The system state has.</p><p>That is why risk can&#8217;t live only inside the strategy.</p><div><hr></div><h1>Risk needs to be a gate</h1><p>I prefer to think about risk as a gate between intent and execution:</p><pre><code><code>Strategy Signal
      |
      v
  Risk Gate
    /   \
  BLOCK ALLOW
           |
           v
        Execute</code></code></pre><p>This is useful because the same risk layer can serve completely different strategies.</p><p>A strategy might be:</p><ul><li><p>momentum</p></li><li><p>arbitrage</p></li><li><p>market making</p></li><li><p>copy trading</p></li><li><p>another short-horizon approach</p></li></ul><p>The risk controls shouldn&#8217;t have to be rewritten every time the strategy changes.</p><p>The strategy produces intent.</p><p>The risk layer evaluates whether that intent is permitted.</p><div><hr></div><h1>Position limits sound simple until you calculate the result</h1><p>Suppose the current position is:</p><pre><code><code>80</code></code></pre><p>The maximum allowed position is:</p><pre><code><code>100</code></code></pre><p>The strategy wants to buy:</p><pre><code><code>30</code></code></pre><p>Checking only the current position gives:</p><pre><code><code>80 &lt; 100</code></code></pre><p>which looks safe.</p><p>But the resulting position is:</p><pre><code><code>80 + 30 = 110</code></code></pre><p>So the trade should be blocked.</p><p>This seems obvious, but the general lesson is important:</p><blockquote><p><strong>Risk checks should evaluate the state after the proposed trade, not only the state before it.</strong></p></blockquote><p>That applies to:</p><ul><li><p>position</p></li><li><p>market exposure</p></li><li><p>total exposure</p></li><li><p>capital utilization</p></li><li><p>inventory</p></li></ul><div><hr></div><h1>Market exposure and portfolio exposure are different</h1><p>An individual market can be within its limit while the overall system is too concentrated.</p><p>Imagine:</p><pre><code><code>Market A    $8,000
Market B    $5,000
Market C    $7,000</code></code></pre><p>Each position might be acceptable independently.</p><p>But the portfolio total is:</p><pre><code><code>$20,000</code></code></pre><p>A new trade that looks harmless at the market level can still push the total portfolio beyond its allowed exposure.</p><p>So I prefer two levels of risk:</p><pre><code><code>Per-Market Risk
       +
Portfolio Risk</code></code></pre><p>Then the system can make the decision using both.</p><p>This becomes even more important when multiple strategies share the same capital or execution infrastructure.</p><div><hr></div><h1>Daily loss should be a system rule</h1><p>Another straightforward control is a daily loss threshold.</p><p>The exact calculation depends on how the trading system defines realized and unrealized P&amp;L, but the operational model is simple:</p><pre><code><code>Daily P&amp;L
   &#8595;
Compare with policy
   &#8595;
Within limit &#8594; Continue
Over limit   &#8594; Pause</code></code></pre><p>Once the configured threshold has been reached, another attractive signal should not automatically override it.</p><p>The system has already reached a condition where its operating policy says:</p><pre><code><code>TRADING PAUSED</code></code></pre><p>The important part is that this rule belongs to the system.</p><p>It shouldn&#8217;t be something one strategy can quietly bypass.</p><div><hr></div><h1>Execution failures can become a risk signal</h1><p>Risk isn&#8217;t only about losses.</p><p>Repeated execution failures can tell you that something is wrong with the infrastructure itself.</p><p>For example:</p><pre><code><code>Order 1 &#8594; Failed
Order 2 &#8594; Failed
Order 3 &#8594; Failed
Order 4 &#8594; Failed</code></code></pre><p>At that point, the right question isn&#8217;t necessarily:</p><blockquote><p>&#8220;Can the strategy generate another order?&#8221;</p></blockquote><p>It may be:</p><blockquote><p><strong>&#8220;Why are we continuing to submit orders when execution itself appears unhealthy?&#8221;</strong></p></blockquote><p>A system can define a failure threshold:</p><pre><code><code>Execution Failures
       &#8595;
  Threshold
       &#8595;
    Pause
       &#8595;
Investigate
       &#8595;
    Recover</code></code></pre><p>That connects the execution layer directly to risk management.</p><div><hr></div><h1>Stale market data is a risk condition</h1><p>One of the easiest mistakes is assuming that a connected WebSocket means the data is current.</p><p>It doesn&#8217;t necessarily.</p><p>For example:</p><pre><code><code>Connection:
CONNECTED</code></code></pre><p>while:</p><pre><code><code>Last market event:
10 seconds ago</code></code></pre><p>If the system&#8217;s maximum allowed data age is 2 seconds, the market-data state is stale.</p><p>So:</p><pre><code><code>CONNECTED</code></code></pre><p>and:</p><pre><code><code>HEALTHY</code></code></pre><p>should not automatically mean the same thing.</p><p>The system needs an actual freshness check.</p><p>When the data becomes stale, trading permission can be reduced or blocked according to policy.</p><div><hr></div><h1>Reconnecting doesn&#8217;t automatically make the system safe</h1><p>This connects directly to my earlier work on <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fi-switched-my-polymarket-bot-to-websocket">Polymarket WebSocket recovery</a></strong>.</p><p>Imagine:</p><pre><code><code>Event A
Event B
    &#8595;
Disconnect
    &#8595;
Events missed
    &#8595;
Reconnect</code></code></pre><p>The connection is back.</p><p>But the local state may still be incomplete.</p><p>That&#8217;s why I think of recovery as:</p><pre><code><code>Disconnect
   &#8595;
Pause
   &#8595;
Reconnect
   &#8595;
Rebuild State
   &#8595;
Reconcile
   &#8595;
Verify
   &#8595;
Check Risk
   &#8595;
Resume</code></code></pre><p>A successful reconnect only proves that communication has resumed.</p><p>It doesn&#8217;t prove that your trading state is correct.</p><div><hr></div><h1>Position mismatch should affect trading permission</h1><p>This is where risk controls connect to <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-position-reconciliation">Polymarket position reconciliation</a></strong>.</p><p>Suppose the system believes:</p><pre><code><code>Expected position: 100</code></code></pre><p>while the external state says:</p><pre><code><code>Observed position: 40</code></code></pre><p>Now the system has a problem.</p><p>It doesn&#8217;t necessarily mean the market strategy is wrong.</p><p>It means the system does not currently have a trustworthy view of its own position.</p><p>That can affect:</p><ul><li><p>exposure</p></li><li><p>future orders</p></li><li><p>sizing</p></li><li><p>hedging</p></li><li><p>risk decisions</p></li></ul><p>So the natural response is:</p><pre><code><code>POSITION MISMATCH
       &#8595;
TRADING BLOCKED
       &#8595;
RECONCILIATION
       &#8595;
    VERIFY</code></code></pre><p>The important thing is that the mismatch becomes an explicit state instead of being hidden inside a number.</p><div><hr></div><h1>Execution verification belongs in the same chain</h1><p>This is also why I built the <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">Polymarket Execution Verifier</a></strong>.</p><p>Execution verification answers:</p><blockquote><p><strong>What actually happened to the trade?</strong></p></blockquote><p>Risk control answers:</p><blockquote><p><strong>Given the current verified state, should the system continue trading?</strong></p></blockquote><p>For example:</p><pre><code><code>Order = FILLED
Transaction = UNKNOWN
Position = UNKNOWN</code></code></pre><p>The strategy might still have a strong signal.</p><p>But the system has unresolved execution state.</p><p>That should be able to propagate into:</p><pre><code><code>TRADING BLOCKED</code></code></pre><p>until verification and reconciliation are complete.</p><div><hr></div><h1><code>FILLED</code> shouldn&#8217;t automatically mean &#8220;safe to continue&#8221;</h1><p>This is a recurring theme in the infrastructure I&#8217;m building.</p><p>A fill is one part of the lifecycle:</p><pre><code><code> Order
   &#8595;
 Fill
   &#8595;
Transaction
   &#8595;
Confirmation
   &#8595;
Settlement
   &#8595;
Position</code></code></pre><p>The fact that a fill occurred doesn&#8217;t automatically prove that the whole resulting system state is correct.</p><p>That&#8217;s why I&#8217;m treating <strong>execution verification</strong> as a separate layer rather than embedding it inside the strategy.</p><p>A production system needs to know the difference between:</p><pre><code><code>Execution Verifie</code></code></pre><p>and:</p><pre><code><code>Position Verified</code></code></pre><p>and:</p><pre><code><code>Risk Verified</code></code></pre><p>Those states build on each other.</p><div><hr></div><h1>Pre-trade risk checks aren&#8217;t enough</h1><p>A common architecture is:</p><pre><code><code>Strategy
   &#8595;
 Risk
   &#8595;
Execute</code></code></pre><p>That&#8217;s necessary.</p><p>But the state can change after the trade.</p><p>So I prefer a loop:</p><pre><code><code>Strategy
   &#8595;
 Risk
   &#8595;
Execute
   &#8595;
Verify
   &#8595;
Reconcile
   &#8595;
Recalculate Risk
   &#8595;
Next Decision</code></code></pre><p>The system is therefore continuously evaluating the state that future decisions depend on.</p><p>Risk isn&#8217;t a one-time check.</p><p>It&#8217;s part of the control loop.</p><div><hr></div><h1>The control plane becomes the final operational layer</h1><p>This is where the <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">Polymarket Trading Control Plane</a></strong> fits.</p><p>The control plane can consume:</p><pre><code><code>Health
Risk
Execution
Position
Reconciliation
Recovery</code></code></pre><p>and turn those signals into operational state.</p><p>For example:</p><pre><code><code>Healthy
   &#8595;
Risk Breach
   &#8595;
Paused</code></code></pre><p>Or:</p><pre><code><code>Disconnected
   &#8595;
Recovering
   &#8595;
Reconcile
   &#8595;
Verify
   &#8595;
Risk Check
   &#8595;
Healthy</code></code></pre><p>The strategy doesn&#8217;t need to understand every one of these states.</p><p>The control plane coordinates them.</p><div><hr></div><h1>Pause isn&#8217;t the same as kill</h1><p>I also think these should remain separate operational concepts.</p><p>A normal pause could happen because:</p><pre><code><code>market data is stale
position needs reconciliation
execution is uncertain
exposure is temporarily too high</code></code></pre><p>The system can potentially recover and resume after the required checks pass.</p><p>A kill switch is stronger.</p><p>It should represent an explicit emergency condition where normal resume logic cannot simply override the state.</p><p>That&#8217;s a control-plane responsibility, not a strategy feature.</p><div><hr></div><h1>When should the bot stop?</h1><p>This is probably the most useful question for a real automated trading system.</p><p>Not:</p><blockquote><p>&#8220;Can the strategy find another trade?&#8221;</p></blockquote><p>But:</p><blockquote><p><strong>&#8220;What conditions make another trade unacceptable right now?&#8221;</strong></p></blockquote><p>For example:</p><pre><code><code>Position limit breached
OR
Portfolio exposure too high
OR
Daily loss threshold reached
OR
Market data stale
OR
Execution state unknown
OR
Position mismatch
OR
Critical execution failures
OR
Recovery incomplete
       &#8595;
TRADING BLOCKED</code></code></pre><p>That is effectively a <strong>trading-permission engine</strong>.</p><div><hr></div><h1>What &#8220;safe to continue&#8221; actually means</h1><p>I don&#8217;t think the system should define safety as one signal.</p><p>It should be a combination of verified conditions:</p><pre><code><code>Market data healthy
+
Execution state verified
+
Position reconciled
+
Exposure within limits
+
Risk within limits
+
Recovery complete
=
TRADING ALLOWED</code></code></pre><p>Otherwise:</p><pre><code><code>PAUSE
   &#8595;
RECONCILE
   &#8595;
VERIFY
   &#8595;
RECOVER
   &#8595;
RECHECK RISK
   &#8595;
RESUME</code></code></pre><p>That is a much stronger model than simply checking whether the bot process is still running.</p><div><hr></div><h1>What I&#8217;m building around Polymarket</h1><p>This is the direction my Polymarket infrastructure work has been moving toward.</p><p>The broader stack looks like:</p><pre><code><code>Polymarket Trading Bot
        &#8595;
   Strategy
        &#8595;
      Risk
        &#8595;
    Execution
        &#8595;
Execution Verifier
        &#8595;
Position Reconciliation
        &#8595;
Trading Control Plane
        &#8595;
Monitoring / Recovery</code></code></pre><p>Each component has a different responsibility.</p><p>The bot generates decisions.</p><p>The risk layer controls what the system is allowed to do.</p><p>Execution carries out the intent.</p><p>The verifier determines what actually happened.</p><p>Reconciliation checks whether state matches reality.</p><p>The control plane coordinates health, risk, recovery, and trading permissions.</p><div><hr></div><h1>The checklist I want a production bot to answer</h1><p>Before allowing a new trade:</p><pre><code><code>[ ] Is market data fresh?
[ ] Is the connection healthy?
[ ] Is execution state verified?
[ ] Is the current position known?
[ ] Is reconciliation complete?
[ ] Is the resulting position within limits?
[ ] Is market exposure within limits?
[ ] Is total exposure within limits?
[ ] Is daily loss within limits?
[ ] Are execution failures below the threshold?
[ ] Is recovery complete?
[ ] Is trading permission ALLOW?</code></code></pre><p>The important part isn&#8217;t that every condition will always be positive.</p><p>The important part is that the system <strong>knows the answer</strong>.</p><div><hr></div><h1>The real goal of risk controls</h1><p>Risk controls aren&#8217;t there to make a trading bot stop trading all the time.</p><p>They&#8217;re there to define the conditions under which trading is allowed to continue.</p><p>Without that layer, the system can keep submitting orders through:</p><pre><code><code>stale data
wrong positions
execution uncertainty
risk breaches
recovery</code></code></pre><p>At that point, the bot isn&#8217;t really operating under a controlled policy.</p><p>It&#8217;s just continuing because nothing stopped it.</p><p>That&#8217;s a very different system.</p><div><hr></div><h1>Final thought</h1><p>A Polymarket trading bot doesn&#8217;t only need to know:</p><blockquote><p><strong>&#8220;When should I trade?&#8221;</strong></p></blockquote><p>It needs to know:</p><blockquote><p><strong>&#8220;When should I refuse to trade?&#8221;</strong></p></blockquote><p>That leads to a much more complete architecture:</p><pre><code><code>Signal
   &#8595;
Risk Check
   &#8595;
Execution
   &#8595;
Verification
   &#8595;
Reconciliation
   &#8595;
Risk Recheck
   &#8595;
Continue / Pause</code></code></pre><p>And that is the direction I&#8217;m building toward with the broader Polymarket stack.</p><p>The strategy generates the intent.</p><p>The infrastructure determines whether that intent is currently permitted.</p><p>When the system knows its state, verifies its executions, reconciles its positions, and stays within its configured risk boundaries, it has a basis for continuing.</p><p>When it doesn&#8217;t:</p><p><strong>stop, reconcile, verify, and recover first.</strong></p>]]></content:encoded></item><item><title><![CDATA[Your Polymarket Bot Says “Filled.” That Doesn’t Mean the Trade Is Done.]]></title><description><![CDATA[Execution needs to be verified across fills, transactions, settlement, and position state before a trading system can safely continue.]]></description><link>https://casatrick.substack.com/p/polymarket-bot-execution-verification</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-bot-execution-verification</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Wed, 30 Sep 2026 10:41:15 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae0e9841-86ea-4190-8735-6c2efdc0ff0a_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A trading bot can say <code>FILLED</code> while the system still doesn&#8217;t know whether the trade is truly complete.</p><p>That sounds like a small distinction.</p><p>In an automated trading system, it can become a very expensive one.</p><p>The problem isn&#8217;t always the strategy.</p><p>Sometimes the strategy generated the correct signal, the bot sent the correct order, and the order even appeared to fill.</p><p>The problem happens <strong>after that</strong>.</p><p>What does the system actually know?</p><p>Did the entire quantity fill?</p><p>Is the transaction known?</p><p>Was it confirmed?</p><p>Did settlement complete?</p><p>Does the account position now match what the bot expects?</p><p>And, most importantly:</p><p><strong>Is the system in a state where it can safely trade again?</strong></p><p>That is the problem I&#8217;m focusing on with a project I&#8217;m building: a <strong>Polymarket Execution Verifier</strong>.</p><p><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">GitHub - Polymarket Execution Verifier</a></p><div><hr></div><h2><code>FILLED</code> is an event. It shouldn&#8217;t automatically mean <code>DONE</code>.</h2><p>A simple trading bot often has logic that effectively looks like this:</p><pre><code><code>signal
  &#8595;
submit order
  &#8595;
filled
  &#8595;
update position
  &#8595;
keep trading
</code></code></pre><p>That model is easy to understand.</p><p>It is also hiding a lot of assumptions.</p><p>A production-oriented system needs to distinguish between:</p><pre><code><code>INTENDED
&#8595;
SUBMITTED
&#8595;
ACCEPTED
&#8595;
MATCHED
&#8595;
FILLED
&#8595;
TX_PENDING
&#8595;
CONFIRMED
&#8595;
SETTLED
&#8595;
POSITION VERIFIED
</code></code></pre><p>And there are states that represent failure or uncertainty:</p><pre><code><code>REJECTED
CANCELLED
FAILED
RETRYING
UNKNOWN
INCONSISTENT
</code></code></pre><p>The difference matters because the system should behave differently in each state.</p><p>A <code>FILLED</code> order and a <code>POSITION VERIFIED</code> trade are not necessarily the same thing.</p><div><hr></div><h1>Consider a very normal failure</h1><p>Imagine your bot wants to buy 100 shares.</p><p>It submits:</p><pre><code><code>BUY 100</code></code></pre><p>Then the system observes:</p><pre><code><code>FILLED</code></code></pre><p>The naive implementation updates its internal position by 100.</p><p>Now imagine the actual situation is:</p><pre><code><code>Requested: 100
Matched:    40
Remaining:  60</code></code></pre><p>The bot&#8217;s local state says:</p><pre><code><code>+100</code></code></pre><p>Reality says:</p><pre><code><code>+40</code></code></pre><p>Now the next strategy decision is being made against the wrong position.</p><p>That affects exposure.</p><p>It affects risk.</p><p>It can affect the next order.</p><p>And once the local state starts drifting from external state, the original strategy may no longer be the thing driving the risk.</p><p>The state error is.</p><p>This is why execution verification deserves to be treated as infrastructure rather than as a small callback inside the strategy.<br><br>This is closely related to how I handle <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-partial-fills-trading-bot">Polymarket partial fills</a></strong>, where requested quantity and actual execution have to remain separate.</p><div><hr></div><h1>The execution lifecycle I care about</h1><p>I&#8217;ve started thinking about execution as a chain of increasingly stronger evidence.</p><h3>1. Order</h3><p>The system created and submitted an intention.</p><pre><code><code>ORDER</code></code></pre><p>This tells us what we wanted to do.</p><p>It does not tell us what actually happened.</p><h3>2. Fill</h3><p>The order was matched, partially or fully.</p><pre><code><code>FILL</code></code></pre><p>Now we have evidence about executed quantity.</p><p>But we may still need to verify what happened downstream.</p><h3>3. Transaction</h3><p>The relevant transaction becomes known.</p><pre><code><code>TRANSACTION</code></code></pre><p>Now the execution can be connected to the underlying transaction state.</p><h3>4. Confirmation</h3><p>The transaction reaches the expected confirmation state.</p><pre><code><code>CONFIRMATION</code></code></pre><p>This is stronger evidence than merely seeing a fill event.</p><h3>5. Settlement</h3><p>The trade reaches the expected final settlement state.</p><pre><code><code>SETTLEMENT</code></code></pre><p>Now the lifecycle has moved significantly closer to completion.</p><h3>6. Position</h3><p>The final question is:</p><pre><code><code>Does the position match what the system expects?</code></code></pre><p>That&#8217;s a separate verification step.</p><p>And that&#8217;s the part that matters operationally.</p><div><hr></div><h1>The uncomfortable state is <code>UNKNOWN</code></h1><p>Most systems are comfortable with:</p><pre><code><code>SUCCESS
FAILURE</code></code></pre><p>Real trading infrastructure often encounters something much less convenient:</p><pre><code><code>UNKNOWN</code></code></pre><p>For example:</p><pre><code><code>FILLED
&#8595;
transaction information unavailable</code></code></pre><p>What should the bot do?</p><p>It shouldn&#8217;t pretend the trade is definitely complete.</p><p>It should retain the uncertainty.</p><p>Something like:</p><pre><code><code>FILLED
&#8594; TX_PENDING</code></code></pre><p>or:</p><pre><code><code>FILLED
&#8594; UNKNOWN</code></code></pre><p>depending on what the system has actually verified.</p><p>The key principle is simple:</p><blockquote><p><strong>Unknown should be a real state, not an error that gets silently converted into success.</strong></p></blockquote><p>That&#8217;s one of the ideas I want the execution-verification layer to enforce.</p><div><hr></div><h1>Then there is the WebSocket problem</h1><p>Real-time systems introduce another source of uncertainty.</p><p>Suppose the bot receives:</p><pre><code><code>event 101
event 102</code></code></pre><p>Then the connection drops.</p><p>While disconnected:</p><pre><code><code>event 103
event 104</code></code></pre><p>happen.</p><p>The socket reconnects.</p><p>The connection is healthy again.</p><p>But the local state may still be missing those events.</p><p>So:</p><pre><code><code>connected = true</code></code></pre><p>doesn&#8217;t necessarily mean:</p><pre><code><code>state = correct</code></code></pre><p>This is why I don&#8217;t think of reconnection as recovery.</p><p>A safer lifecycle is:</p><pre><code><code>DISCONNECT
&#8595;
PAUSE
&#8595;
RECONNECT
&#8595;
REBUILD
&#8595;
RECONCILE
&#8595;
VERIFY
&#8595;
RESUME</code></code></pre><p>The important part isn&#8217;t reconnecting.</p><p>It&#8217;s <strong>knowing what changed while you were away</strong>.<br><br>A reconnect alone isn't enough. I wrote more about <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fi-switched-my-polymarket-bot-to-websocket">rebuilding Polymarket trading state after a WebSocket disconnect</a></strong> and why recovery requires more than simply opening the connection again.</p><div><hr></div><h1>Execution verification and reconciliation are related - but different</h1><p>I&#8217;ve been building these as separate concepts.</p><h3>Execution verification asks:</h3><blockquote><p><strong>What actually happened to the trade?</strong></p></blockquote><p>It follows the execution lifecycle:</p><pre><code><code>order
&#8594; fill
&#8594; transaction
&#8594; confirmation
&#8594; settlement</code></code></pre><h3>Position reconciliation asks:</h3><blockquote><p><strong>Does my system&#8217;s state match the external state?</strong></p></blockquote><p>For example:</p><pre><code><code>Expected position: 125.5
Observed position: 100.0</code></code></pre><p>Now you have a mismatch.</p><p>And an important thing can happen:</p><pre><code><code>Execution = VERIFIED
Position  = MISMATCH</code></code></pre><p>The transaction may be completely verified while your application&#8217;s position state is still wrong.</p><p>That&#8217;s why one mechanism shouldn&#8217;t be responsible for answering every question.<br><br>This is where <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-position-reconciliation">Polymarket position reconciliation</a></strong> becomes a separate layer: execution verification tells you what happened to the trade, while reconciliation checks whether your system's state actually matches the account.</p><div><hr></div><h1>What a production trading system needs after the strategy</h1><p>This is the direction my Polymarket infrastructure work has been moving toward.</p><p>Instead of:</p><pre><code><code>market data
+
strategy
+
order placement</code></code></pre><p>I think about the system more like:</p><pre><code><code>market data
+
strategy
+
execution
+
execution verification
+
position reconciliation
+
risk controls
+
recovery
+
observability</code></code></pre><p>The strategy tells the system what it wants to do.</p><p>The infrastructure has to determine whether reality matches that intention.</p><p>That distinction becomes increasingly important as the bot handles more positions, more markets, more execution events, and more failure modes.</p><div><hr></div><h1>The execution verifier sits between the order and the rest of the system</h1><p>The architecture I&#8217;m working with looks roughly like this:</p><pre><code><code>Trading Bot / Strategy
        &#9474;
        &#9660;
   Order Manager
        &#9474;
        &#9660;
 Execution Verifier
        &#9474;
        &#9500;&#9472;&#9472; Order
        &#9500;&#9472;&#9472; Fill
        &#9500;&#9472;&#9472; Transaction
        &#9500;&#9472;&#9472; Confirmation
        &#9500;&#9472;&#9472; Settlement
        &#9492;&#9472;&#9472; Position
        &#9474;
        &#9660;
    Reconciliation
        &#9474;
        &#9660;
 Risk &amp; Control Plane
        &#9474;
        &#9660;
   Resume / Pause</code></code></pre><p>That gives each layer a specific responsibility.</p><p>The verifier asks:</p><blockquote><p><strong>What happened?</strong></p></blockquote><p>Reconciliation asks:</p><blockquote><p><strong>Does my state match reality?</strong></p></blockquote><p>Risk asks:</p><blockquote><p><strong>Are the resulting conditions within configured limits?</strong></p></blockquote><p>The control plane coordinates what happens next.<br><br>I covered the broader system design in <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-trading-bot-architecture">Polymarket trading bot architecture</a></strong>, but execution verification deserves its own layer once the bot has to operate continuously.</p><div><hr></div><h1>Why I think this is more important than another strategy</h1><p>There is a lot of attention around finding better entries, better signals, better models, better arbitrage, and better execution logic.</p><p>Those things matter.</p><p>But once a system is actually running continuously, another class of problems becomes unavoidable:</p><ul><li><p>state drift</p></li><li><p>partial fills</p></li><li><p>delayed information</p></li><li><p>missed events</p></li><li><p>inconsistent positions</p></li><li><p>failed orders</p></li><li><p>stale market data</p></li><li><p>uncertain execution state</p></li><li><p>recovery after restarts</p></li></ul><p>A strategy can be right and the trading system can still be wrong.</p><p>That&#8217;s the distinction I&#8217;m interested in.</p><div><hr></div><h1>The rule I&#8217;m building around</h1><p>I want a trading system to earn the right to resume.</p><p>Not:</p><pre><code><code>socket connected &#8594; resume</code></code></pre><p>Not:</p><pre><code><code>order filled &#8594; position updated</code></code></pre><p>And not:</p><pre><code><code>API returned success &#8594; done</code></code></pre><p>Instead:</p><pre><code><code>execution verified
+
position verified
+
exposure verified
+
market state healthy
+
risk limits healthy
=
eligible to resume</code></code></pre><p>That is a much stronger operational model.</p><p>It also makes failures visible instead of silently folding them into normal trading state.</p><div><hr></div><h1>Building the Polymarket Execution Verifier</h1><p>I&#8217;ve started separating this logic into its own project:</p><p><strong>Polymarket Execution Verifier</strong></p><p><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">GitHub repository</a></p><p>The core lifecycle is:</p><pre><code><code>ORDER
&#8595;
FILL
&#8595;
TRANSACTION
&#8595;
CONFIRMATION
&#8595;
SETTLEMENT
&#8595;
POSITION</code></code></pre><p>The goal isn&#8217;t to create another trading strategy.</p><p>The goal is to make execution state explicit, verifiable, and usable by the rest of the trading system.</p><p>This also fits into the broader Polymarket tooling I&#8217;m building around the trading bot.</p><p><strong>Polymarket Trading Bot</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">https://github.com/casatrickdev/polymarket-trading-bot</a></p><p><strong>Polymarket Trading Control Plane</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">https://github.com/casatrickdev/polymarket-trading-control-plane</a></p><p>The three projects increasingly represent different parts of the same problem:</p><pre><code><code>Trading Bot
   &#8595;
Execute
   &#8595;
Execution Verifier
   &#8595;
Verify
   &#8595;
Position Reconciliation
   &#8595;
Control Plane
   &#8595;
Monitor / Risk / Recover</code></code></pre><div><hr></div><h1>A simple checklist</h1><p>Before treating an execution as complete, the system should be able to answer:</p><pre><code><code>&#10003; Was the order accepted?
&#10003; Was it matched?
&#10003; How much actually filled?
&#10003; Is the remaining quantity known?
&#10003; Is the relevant transaction known?
&#10003; Has the transaction reached the expected state?
&#10003; Is settlement verified?
&#10003; Does the external position match?
&#10003; Is exposure correct?
&#10003; Are risk limits still valid?
&#10003; Is any execution uncertainty unresolved?</code></code></pre><p>The important part is not that every answer must always be yes.</p><p>The important part is that the system <strong>knows the answer</strong>.<br></p><h1>Final thought</h1><p>The difference between a trading bot and production trading infrastructure is often what happens when everything isn&#8217;t perfectly synchronized.</p><p>A signal is easy to generate.</p><p>An order is easy to submit.</p><p>A <code>FILLED</code> event is easy to consume.</p><p>The harder problem is knowing what is actually true after all of that.</p><p>That&#8217;s why I&#8217;m treating execution verification as its own layer:</p><pre><code><code>Don't just ask:

"Did the order fill?"

Ask:

"Can the system verify what happened,
verify the resulting position,
and prove that it is safe to continue?"</code></code></pre><p>That is the kind of infrastructure I&#8217;m interested in building around Polymarket.<br><br><br>This fits into the larger Polymarket infrastructure stack I've been building: <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">trading bot</a></strong> &#8594; execution verification &#8594; <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-position-reconciliation">position reconciliation</a></strong> &#8594; <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">trading control plane</a></strong>.</p>]]></content:encoded></item><item><title><![CDATA[Your Polymarket Bot Reconnected. Should It Really Start Trading Again?]]></title><description><![CDATA[A WebSocket reconnect only restores the connection. A trading system still needs to reconcile state, verify positions, check risk, and recover safely.]]></description><link>https://casatrick.substack.com/p/polymarket-websocket-recovery</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-websocket-recovery</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Tue, 29 Sep 2026 06:00:33 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d055c9a-6755-436d-b563-d22bd797afeb_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Your Polymarket trading bot is connected to the WebSocket.</p><p>Then the connection drops.</p><p>A few seconds later, it reconnects.</p><p>The process is running again.</p><p>Should it immediately start trading?</p><p>I don&#8217;t think so.</p><p>A successful reconnect only proves that the network connection has returned.</p><p>It doesn&#8217;t prove that the trading system knows what happened while it was disconnected.</p><p>An order may have changed.</p><p>A fill may have occurred.</p><p>A position may have changed.</p><p>An event may have been missed.</p><p>The local state may now be stale.</p><p>That&#8217;s why I&#8217;m working on <strong>Polymarket WebSocket recovery</strong> as part of the broader <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">Polymarket Trading Control Plane</a></strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">.</a></p><p>The core idea is:</p><pre><code><code>Disconnect
    &#8595;
Pause
    &#8595;
Reconnect
    &#8595;
Reconcile
    &#8595;
Verify
    &#8595;
Risk Check
    &#8595;
Resume</code></code></pre><div><hr></div><h1>A WebSocket reconnect is only the beginning</h1><p>For a normal application, a reconnect can be enough.</p><p>For an automated trading system, it isn&#8217;t.</p><p>Imagine this sequence:</p><pre><code><code>Order submitted
      &#8595;
WebSocket disconnects
      &#8595;
Execution event occurs
      &#8595;
Connection unavailable
      &#8595;
WebSocket reconnects</code></code></pre><p>The connection is back.</p><p>But the application may not know what happened during the gap.</p><p>That creates a much more important question:</p><blockquote><p><strong>What state is the trading system in now?</strong></p></blockquote><p>The Control Plane is designed around exactly this distinction between connectivity and verified trading state. Its architecture treats WebSocket streams and API reads as inputs into event ingestion and state reconciliation rather than assuming that reconnecting restores everything automatically.<br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;76e24d5d-1a77-4e75-89f1-1ba7b6a30709&quot;,&quot;caption&quot;:&quot;Speed is supposed to be an advantage.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;I Switched My Polymarket Bot to WebSocket. The Results Were Not What I Expected.&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-06-22T07:16:49.318Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/i-switched-my-polymarket-bot-to-websocket&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:203052461,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1>The dangerous part: nothing has to crash</h1><p>This is what makes WebSocket failures interesting in trading systems.</p><p>A process can remain alive.</p><p>The API can still respond.</p><p>The application can reconnect.</p><p>And the trading state can still be wrong.</p><p>For example:</p><pre><code><code>Process:       RUNNING
WebSocket:     CONNECTED
API:           OK
Strategy:      ACTIVE</code></code></pre><p>while:</p><pre><code><code>Position state: UNVERIFIED</code></code></pre><p>That is not the same thing as a healthy trading system.</p><p>The Control Plane therefore uses explicit operational states such as:</p><pre><code><code>HEALTHY
DEGRADED
PAUSED
RECOVERING
FAILED</code></code></pre><p>rather than treating process uptime as the complete definition of system health.</p><div><hr></div><h1>What can happen during a disconnect?</h1><p>A WebSocket gap can create several different problems.</p><h3>Missed events</h3><p>An order, fill, or position update may never reach the local application.</p><h3>Duplicate events</h3><p>The same event may be processed twice around reconnect logic.</p><h3>Delayed events</h3><p>An event may arrive long after the system expected it.</p><h3>Out-of-order events</h3><p>Related state transitions may be observed in an unexpected sequence.</p><h3>Restart during the gap</h3><p>The application can lose in-memory state while disconnected.</p><h3>Unknown state</h3><p>The system may simply not know whether an action succeeded.</p><p>These are not necessarily independent problems.</p><p>They can cascade:</p><pre><code><code>Disconnect
   &#8595;
Missed event
   &#8595;
State drift
   &#8595;
Position mismatch
   &#8595;
Incorrect exposure
   &#8595;
Incorrect risk decision</code></code></pre><div><hr></div><h1>Reconnect is not recovery</h1><p>This is the main design principle behind this project.</p><p>A reconnect answers:</p><blockquote><p><strong>Can I connect again?</strong></p></blockquote><p>Recovery answers:</p><blockquote><p><strong>Can I prove that the trading system is safe to operate again?</strong></p></blockquote><p>Those are different questions.</p><p>The flow I want is:</p><pre><code><code>WebSocket disconnect
        &#8595;
Trading = PAUSED
        &#8595;
Reconnect
        &#8595;
Read current state
        &#8595;
   Compare
        &#8595;
    Repair
        &#8595;
    Verify
        &#8595;
Risk check
        &#8595;
    Resume</code></code></pre><p>The Control Plane&#8217;s recovery model explicitly includes reconnects, restarts, suspected event gaps, unexpected API responses, and state mismatches as reasons to reconcile state.</p><div><hr></div><h1>Why pause trading?</h1><p>Suppose the system loses its WebSocket connection.</p><p>The simplest implementation is:</p><pre><code><code>disconnect
   &#8595;
reconnect
   &#8595;
continue trading</code></code></pre><p>The problem is the middle.</p><p>What if the local position is stale?</p><p>What if the bot missed a fill?</p><p>What if an order is still open?</p><p>What if exposure changed while the system was disconnected?</p><p>Continuing to place new orders before answering those questions can turn an infrastructure problem into a trading problem.</p><p>A safer model is:</p><pre><code><code>Unknown state
    &#8595;
No new risk
    &#8595;
Recover
    &#8595;
Verify
    &#8595;
Resume</code></code></pre><p>The Control Plane is explicitly designed around operational actions such as pause, resume, kill switch, and state reconciliation.</p><div><hr></div><h1>What should be checked after reconnect?</h1><p>I don&#8217;t think the reconnect handler should simply set:</p><pre><code><code>connected = true</code></code></pre><p>It should eventually establish something closer to:</p><pre><code><code>[&#10003;] WebSocket healthy
[&#10003;] Market data fresh
[&#10003;] Orders known
[&#10003;] Fills known
[&#10003;] Positions verified
[&#10003;] Exposure verified
[&#10003;] Risk limits satisfied
[&#10003;] No critical mismatch</code></code></pre><p>Only then does the system have a strong basis for resuming normal trading.</p><div><hr></div><h1>State reconciliation after a WebSocket gap</h1><p>The reconciliation model is straightforward:</p><pre><code><code>Local State
     &#8595;
Remote State
     &#8595;
Compare
     &#8595;
Repair
     &#8595;
Verified State</code></code></pre><p>The important part is that local state and remote state are treated as different sources that need to be compared.</p><p>For example:</p><pre><code><code>Local position:
+100

Remote position:
+40</code></code></pre><p>The system shouldn&#8217;t simply choose one because it &#8220;looks right.&#8221;</p><p>It needs to understand the source of the discrepancy.</p><p>Maybe a partial fill happened.</p><p>Maybe an event was missed.</p><p>Maybe the application restarted.</p><p>Maybe an earlier state update failed.</p><p>The reconciliation layer is there to establish a verified state before additional trading risk is allowed.<br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;374bb46a-9153-43ee-896b-5f4825e26cfc&quot;,&quot;caption&quot;:&quot;Your Polymarket trading bot says:&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;When Your Polymarket Trading Bot Can&#8217;t Trust Its Own State&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-09-28T11:16:44.308Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/448b45d9-28ad-4c09-bacf-a13de98bb507_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/polymarket-position-reconciliation&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:217810424,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1>WebSocket recovery is not only about positions</h1><p>The Control Plane separates:</p><pre><code><code>Orders
   &#8595;
Trades / Fills
   &#8595;
Positions
   &#8595;
Exposure
   &#8595;
Risk</code></code></pre><p>That means recovery should not stop at:</p><blockquote><p>&#8220;My position looks okay.&#8221;</p></blockquote><p>The broader system also needs to know:</p><ul><li><p>whether orders are still open</p></li><li><p>whether fills were processed</p></li><li><p>whether exposure is correct</p></li><li><p>whether risk limits remain satisfied</p></li><li><p>whether the market-data stream is healthy</p></li></ul><p>The project explicitly defines these as separate state and health areas.</p><div><hr></div><h1>A reconnect after a partial fill</h1><p>Consider:</p><pre><code><code>Requested:
100

Filled:
40</code></code></pre><p>The WebSocket then disconnects.</p><p>What happened to the remaining 60?</p><p>Possibilities include:</p><pre><code><code>Still Open
Cancelled
Filled Later
Unknown</code></code></pre><p>When the connection returns, the system should not assume the answer.</p><p>It needs to reconcile.</p><p>The flow becomes:</p><pre><code><code>Partial Fill
      &#8595;
WebSocket Gap
      &#8595;
Reconnect
      &#8595;
Check Execution State
      &#8595;
Check Position
      &#8595;
Check Exposure
      &#8595;
Verify</code></code></pre><p>This is why WebSocket recovery and partial-fill handling are related but still different problems.<br>Read the article: </p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3dd0481a-fd6a-42b3-9266-67f4c282e312&quot;,&quot;caption&quot;:&quot;Imagine your Polymarket trading bot sends an order for 100.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Your Polymarket Order Filled. So Why Is Your Position Still Wrong?&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-09-27T05:17:04.654Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/625c7c53-da88-40d2-99ff-3ccae44aa07f_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/polymarket-partial-fills-trading-bot&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:217626479,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1>A reconnect after an unknown order</h1><p>Another case:</p><pre><code><code>Submit order
      &#8595;
Connection fails
      &#8595;
No final response</code></code></pre><p>Now the order is:</p><pre><code><code>UNKNOWN</code></code></pre><p>It could have:</p><ul><li><p>failed</p></li><li><p>been accepted</p></li><li><p>partially filled</p></li><li><p>fully filled</p></li></ul><p>Blindly sending it again could create duplicate exposure.</p><p>A safer path is:</p><pre><code><code>UNKNOWN
   &#8595;
PAUSE
   &#8595;
RECONCILE
   &#8595;
DETERMINE ACTUAL STATE
   &#8595;
CONTINUE ACCORDING TO POLICY</code></code></pre><p>An automated trading system needs to be comfortable representing uncertainty.</p><div><hr></div><h1>Application restarts are another recovery case</h1><p>WebSocket recovery doesn&#8217;t end with networking.</p><p>Suppose the entire trading application restarts.</p><p>On startup, it may only know what was persisted locally.</p><p>That isn&#8217;t necessarily the latest account state.</p><p>A safer startup path is:</p><pre><code><code>Application starts
        &#8595;
Load local state
        &#8595;
Connect
        &#8595;
Read remote state
        &#8595;
Compare
        &#8595;
Repair
        &#8595;
Verify
        &#8595;
Risk check
        &#8595;
Allow trading</code></code></pre><p>Starting the process and allowing trading should therefore be separate decisions.</p><div><hr></div><h1>The recovery state machine</h1><p>The mental model I&#8217;m building around this is:</p><pre><code><code>              HEALTHY
                  &#8595;
             DISCONNECTED
                  &#8595;
              DEGRADED
                  &#8595;
               PAUSED
                  &#8595;
              RECOVERING
                  &#8595;
             RECONCILING
                  &#8595;
               VERIFIED
                  &#8595;
                HEALTHY</code></code></pre><p>The actual implementation can stay simpler than this diagram.</p><p>What matters is that the system knows whether it is:</p><ul><li><p>operating normally</p></li><li><p>degraded</p></li><li><p>paused</p></li><li><p>recovering</p></li><li><p>verified</p></li></ul><p>rather than only knowing whether the socket happens to be connected.</p><div><hr></div><h1>Observability during recovery</h1><p>Recovery shouldn&#8217;t happen inside a black box.</p><p>The system should expose events such as:</p><pre><code><code>WEBSOCKET_DISCONNECTED
RECONCILIATION_STARTED
STATE_MISMATCH
RECONCILIATION_COMPLETED
TRADING_PAUSED
TRADING_RESUMED</code></code></pre><p>Other operational events can include:</p><pre><code><code>ORDER_FAILURE
PARTIAL_FILL
MARKET_DATA_STALE
RISK_LIMIT_BREACHED
KILL_SWITCH_TRIGGERED</code></code></pre><p>These can feed:</p><pre><code><code>Dashboard
Logs
Alerts
Webhooks
External Monitoring</code></code></pre><p>The Control Plane&#8217;s event model is designed around machine-readable operational events for exactly this kind of behavior.</p><div><hr></div><h1>Risk should be checked after recovery</h1><p>Imagine the system reconnects and successfully reconciles its positions.</p><p>It still shouldn&#8217;t blindly resume.</p><p>Exposure might have changed.</p><p>A daily loss threshold may have been reached.</p><p>Market data may still be stale.</p><p>The system may have accumulated execution failures.</p><p>So the final step should be:</p><pre><code><code>Reconcile
   &#8595;
Verify
   &#8595;
Risk Check
   &#8595;
ALLOW</code></code></pre><p>or:</p><pre><code><code>Reconcile
   &#8595;
Mismatch / Risk Breach
   &#8595;
REMAIN PAUSED</code></code></pre><p>This keeps the control layer independent from the specific strategy.</p><div><hr></div><h1>What I want to avoid</h1><p>I don&#8217;t want recovery code that looks like:</p><pre><code><code>if connected:
    trade()</code></code></pre><p>or:</p><pre><code><code>on_reconnect():
    resume()</code></code></pre><p>That makes connectivity the authority over trading.</p><p>I&#8217;d rather have something closer to:</p><pre><code><code>on_disconnect():
    pause()

on_reconnect():
    reconcile()
    verify()
    check_risk()

if state_verified &amp;&amp; risk_ok:
    resume()</code></code></pre><p>The exact implementation will evolve, but the principle is clear:</p><blockquote><p><strong>Connectivity should not be the thing that decides whether trading resumes.</strong></p></blockquote><div><hr></div><h1>Testing WebSocket recovery</h1><p>The interesting tests aren&#8217;t only:</p><blockquote><p>&#8220;Does the socket reconnect?&#8221;</p></blockquote><p>They are:</p><p>ScenarioExpected behaviorClean disconnectReconnectMissed eventReconcileDuplicate eventAvoid double-processingDelayed eventValidate current statePartial fill during gapReconcile actual fillUnknown orderBlock blind retryRestart during gapReload and reconcilePosition mismatchPauseStale market dataPauseRisk breachPause or kill</p><p>The broader Control Plane roadmap already treats these kinds of failure scenarios as first-class test cases.</p><div><hr></div><h1>How this fits with the Control Plane</h1><p>The Control Plane sits around the trading system:</p><pre><code><code>                 POLYMARKET
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474;                       &#9474;
     WebSocket Streams          API / Reads
          &#9474;                       &#9474;
          &#9660;                       &#9660;
       Event Ingestion      State Reconciler
          &#9474;                       &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                      &#9660;
                  State Store
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9660;           &#9660;           &#9660;
       Risk        Health       Alerts
          &#9474;           &#9474;           &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                      &#9660;
                Control Plane
                      &#9474;
           Pause / Resume / Kill</code></code></pre><p>This is intentionally an operational layer around automated trading rather than another trading strategy. The project is currently in early development.<br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e08283c1-bd17-47e7-bdef-f91e6f563397&quot;,&quot;caption&quot;:&quot;A trading bot can start with market data, a strategy, and an order. But reliable execution requires much more than strategy logic.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Building a Production-Grade Polymarket Trading Bot: The Backend Architecture&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-26T05:54:47.668Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1276caad-37ff-476f-b684-7ab4c7fe7f9d_1731x909.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/polymarket-trading-bot-architecture&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:212804892,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:25,&quot;comment_count&quot;:5,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h1>The broader Polymarket projects</h1><p>I&#8217;m approaching these as different layers of the same trading-system architecture.</p><h3><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">Polymarket Trading Bot</a></h3><p>The strategy and automated trading layer.</p><h3><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">Polymarket Execution Verifier</a></h3><p>The execution-verification layer:</p><pre><code><code>Order
 &#8595;
Fill
 &#8595;
Transaction
 &#8595;
Settlement
 &#8595;
Position</code></code></pre><h3>Polymarket Trading Control Plane</h3><p>The operational layer:</p><pre><code><code>State
Risk
Health
Reconciliation
Alerts
Recovery</code></code></pre><p>Together:</p><pre><code><code>Trading Bot
    &#8595;
Execution
    &#8595;
Execution Verification
    &#8595;
Control Plane
    &#8595;
Verified State
    &#8595;
Resume</code></code></pre><div><hr></div><h1>The bigger lesson</h1><p>A WebSocket reconnect is easy to implement.</p><p><strong>Safe recovery is much harder.</strong></p><p>The connection can come back while:</p><ul><li><p>state is stale</p></li><li><p>fills are unknown</p></li><li><p>positions are mismatched</p></li><li><p>exposure is incorrect</p></li><li><p>risk conditions have changed</p></li></ul><p>So I don&#8217;t want the system to ask:</p><blockquote><p>&#8220;Am I connected?&#8221;</p></blockquote><p>I want it to ask:</p><blockquote><p><strong>&#8220;Is my trading state verified, and is it safe to continue?&#8221;</strong></p></blockquote><p>That produces a very different recovery flow:</p><pre><code><code>Disconnect
    &#8595;
  Pause
    &#8595;
Reconnect
    &#8595;
Reconcile
    &#8595;
 Repair
    &#8595;
 Verify
    &#8595;
Risk Check
    &#8595;
 Resume</code></code></pre><p>That&#8217;s the problem I&#8217;m exploring with <strong>Polymarket WebSocket recovery</strong> and the broader Trading Control Plane.</p><p>A connection coming back is useful.</p><p>But for an automated trading bot, <strong>the system shouldn&#8217;t resume because the socket is connected. It should resume because the state is trusted.</strong></p>]]></content:encoded></item><item><title><![CDATA[When Your Polymarket Trading Bot Can’t Trust Its Own State]]></title><description><![CDATA[A trading bot can be online while its local state is wrong. Here's how reconciliation can detect, repair, and verify state before trading resumes.]]></description><link>https://casatrick.substack.com/p/polymarket-position-reconciliation</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-position-reconciliation</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Mon, 28 Sep 2026 11:16:44 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F448b45d9-28ad-4c09-bacf-a13de98bb507_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Your Polymarket trading bot says:</p><pre><code><code>Position: +100</code></code></pre><p>But the account says:</p><pre><code><code>Position: +40</code></code></pre><p>The bot is running.</p><p>The API is responding.</p><p>The WebSocket is connected.</p><p>So which state should the trading system trust?</p><p>This is the problem I&#8217;m exploring with <strong>position reconciliation</strong>.</p><p>A trading system can gradually drift away from reality without completely crashing. A missed event, a WebSocket disconnect, an application restart, or an unexpected API response can all leave local state different from the account state the system is supposed to represent.</p><p>The real problem isn&#8217;t:</p><blockquote><p>&#8220;Is the bot running?&#8221;</p></blockquote><p>It&#8217;s:</p><blockquote><p><strong>&#8220;Can the bot trust its own state?&#8221;</strong></p></blockquote><p>That&#8217;s the idea behind the <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">Polymarket Trading Control Plane</a></strong> I&#8217;m building.</p><div><hr></div><h1>A running process doesn&#8217;t mean a correct trading system</h1><p>It&#8217;s easy to define health as:</p><pre><code><code>Process = Running</code></code></pre><p>For an automated trading system, that definition is too small.</p><p>Imagine this sequence:</p><pre><code><code>WebSocket disconnect
        &#8595;
Execution event missed
        &#8595;
Local state not updated
        &#8595;
Position becomes stale
        &#8595;
Risk calculation becomes stale
        &#8595;
Strategy keeps trading</code></code></pre><p>Nothing necessarily crashes.</p><p>There may be no obvious error message.</p><p>The process remains alive.</p><p>The dangerous part is that the system can continue making decisions with incorrect information.</p><p>That is why the Control Plane focuses on <strong>system health, trading state, risk controls, recovery, and operational control</strong>, rather than only whether the application is running.<br><br>The broader <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-trading-bot-architecture">Polymarket trading bot architecture</a></strong> is described here.</p><div><hr></div><h1>What is state drift?</h1><p>State drift is what happens when the system&#8217;s local representation of the trading account no longer matches the state that actually exists remotely.</p><p>For example:</p><pre><code><code>Local position:
+100

Remote position:
+40</code></code></pre><p>The difference is:</p><pre><code><code>-60</code></code></pre><p>That difference can affect:</p><pre><code><code>Position sizing
Exposure
Hedging
Risk limits
Available capital
Next orders</code></code></pre><p>A state mismatch is therefore not simply a display bug.</p><p>It can change what the trading system does next.</p><div><hr></div><h1>Why state can drift</h1><p>There isn&#8217;t one single cause.</p><p>A trading system can lose synchronization through:</p><h3>WebSocket disconnects</h3><p>An event can occur while the connection is unavailable.</p><h3>Missed events</h3><p>The application may not process every event exactly as expected.</p><h3>Application restarts</h3><p>The process may restart with incomplete or outdated local state.</p><h3>Unexpected API responses</h3><p>The application&#8217;s assumptions may differ from the current remote state.</p><h3>Partial execution</h3><p>The intended quantity and actual execution can diverge.</p><h3>Other infrastructure failures</h3><p>The system can continue operating while one part of its state becomes stale.</p><p>These are exactly the kinds of conditions the Control Plane is designed to surface and recover from.<br><br>WebSocket reliability is another important part of maintaining real-time trading state; I covered that transition in my <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fi-switched-my-polymarket-bot-to-websocket">Polymarket WebSocket</a></strong> article.</p><div><hr></div><h1>Reconciliation is how the system checks reality</h1><p>The basic idea is simple:</p><pre><code><code>Local State
     &#8595;
Remote State
     &#8595;
Compare
     &#8595;
Repair
     &#8595;
Verified State</code></code></pre><p>But a trading system has more than one state variable.</p><p>It has a chain of related state:</p><pre><code><code>Orders
   &#8595;
Trades / Fills
   &#8595;
Positions
   &#8595;
Exposure
   &#8595;
Risk</code></code></pre><p>An order is what the system requested.</p><p>A fill is what actually executed.</p><p>A position is what the account holds.</p><p>Exposure is the risk created by that position.</p><p>Risk determines whether another trade should be allowed.</p><p>That means reconciliation should eventually reason about more than a single position number.</p><div><hr></div><h1>Position reconciliation is not just a database query<br></h1><p>It&#8217;s tempting to think reconciliation means:</p><pre><code><code>SELECT local_position
SELECT remote_position

if different:
    update local_position</code></code></pre><p>That is only the simplest version.</p><p>The same principle applies to execution testing. My <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-bot-backtesting">Polymarket bot backtesting</a></strong> work looks at realistic fills, latency, liquidity, and partial execution.<br><br>The difficult part is deciding:</p><blockquote><p><strong>What should be trusted, what should be repaired, and what should remain blocked until the state is verified?</strong></p></blockquote><p>Consider:</p><pre><code><code>Local:
+100

Remote:
+40</code></code></pre><p>The system now needs to establish why the difference exists.</p><p>Maybe:</p><pre><code><code>40 actually filled</code></code></pre><p>Maybe:</p><pre><code><code>60 was cancelled</code></code></pre><p>Maybe:</p><pre><code><code>60 is still open</code></code></pre><p>Maybe:</p><pre><code><code>an event was missed</code></code></pre><p>Maybe:</p><pre><code><code>local state was never updated after a restart</code></code></pre><p>The number <code>+40</code> is useful.</p><p>The explanation behind the number is even more important.</p><div><hr></div><h1>Reconciliation should preserve the state transition</h1><p>One reason I prefer explicit state models is that they make these situations easier to reason about.</p><p>Instead of thinking:</p><pre><code><code>Position changed</code></code></pre><p>the system can reason through:</p><pre><code><code>Order
   &#8595;
Fill
   &#8595;
Position
   &#8595;
Exposure
   &#8595;
Risk</code></code></pre><p>If a mismatch appears, the system can investigate the transition that produced it.</p><p>For example:</p><pre><code><code>Requested:
100

Executed:
40

Position:
+40</code></code></pre><p>That is internally consistent.</p><p>But:</p><pre><code><code>Requested:
100

Executed:
40

Local position:
+100

Remote position:
+40</code></code></pre><p>is not.</p><p>Now the system knows it has state drift.</p><div><hr></div><h1>Reconnect is not reconciliation</h1><p>This is one of the most important distinctions in the design.</p><p>A reconnect answers:</p><blockquote><p><strong>&#8220;Can I connect again?&#8221;</strong></p></blockquote><p>Reconciliation answers:</p><blockquote><p><strong>&#8220;Does my local state match reality?&#8221;</strong></p></blockquote><p>Those are different questions.</p><p>Imagine:</p><pre><code><code>Event A
   &#8595;
WebSocket disconnect
   &#8595;
Events B, C, D
   &#8595;
WebSocket reconnect</code></code></pre><p>The network connection has returned.</p><p>But the application may have missed B, C, and D.</p><p>So:</p><pre><code><code>RECONNECTED</code></code></pre><p>doesn&#8217;t necessarily mean:</p><pre><code><code>STATE VERIFIED</code></code></pre><p>A more deliberate recovery path is:</p><pre><code><code>Reconnect
   &#8595;
Read remote state
   &#8595;
Compare
   &#8595;
Repair
   &#8595;
Verify
   &#8595;
Check risk
   &#8595;
Resume trading</code></code></pre><p>The Control Plane is specifically designed around this separation between connectivity and recovery.</p><div><hr></div><h1>When should reconciliation run?</h1><p>I don&#8217;t think reconciliation should only happen after an obvious failure.</p><p>Useful triggers include:</p><pre><code><code>WebSocket reconnect
Application restart
Suspected event gap
Unexpected API response
State mismatch</code></code></pre><p>These conditions are already part of the Control Plane&#8217;s planned reconciliation model.</p><p>The common theme is uncertainty.</p><p>Whenever the system has reason to believe its local view may no longer be complete, it should have a path back to a verified state.</p><div><hr></div><h1>A position mismatch should affect trading</h1><p>Suppose the bot thinks:</p><pre><code><code>Position = +40</code></code></pre><p>while the actual position is:</p><pre><code><code>Position = +100</code></code></pre><p>The strategy may believe it has room to add another 40.</p><p>Its local model says:</p><pre><code><code>+40 &#8594; +80</code></code></pre><p>The account would actually become:</p><pre><code><code>+100 &#8594; +140</code></code></pre><p>The mismatch has now become a risk problem.</p><p>That is why the control plane should be able to move the system into a controlled state:</p><pre><code><code>Position mismatch
       &#8595;
Trading = PAUSED
       &#8595;
Reconcile
       &#8595;
   Verify
       &#8595;
Risk check
       &#8595;
   Resume</code></code></pre><p>The goal isn&#8217;t to eliminate every mismatch.</p><p>The goal is to prevent an unresolved mismatch from silently becoming additional risk.</p><div><hr></div><h1>Unknown is a valid state</h1><p>One of the most useful states in infrastructure is:</p><pre><code><code>UNKNOWN</code></code></pre><p>Suppose the bot submits an order.</p><p>The network fails.</p><p>The application doesn&#8217;t receive the final response.</p><p>What happened?</p><p>Maybe the order was rejected.</p><p>Maybe it was accepted.</p><p>Maybe it partially filled.</p><p>Maybe it completely filled.</p><p>The system does not know.</p><p>The dangerous response is to pretend that:</p><pre><code><code>UNKNOWN = FAILED</code></code></pre><p>or:</p><pre><code><code>UNKNOWN = FILLED</code></code></pre><p>A safer flow is:</p><pre><code><code>UNKNOWN
   &#8595;
PAUSE
   &#8595;
RECONCILE
   &#8595;
DETERMINE ACTUAL STATE
   &#8595;
CONTINUE ACCORDING TO POLICY</code></code></pre><p>An automated trading system needs to be able to represent uncertainty rather than hiding it.</p><div><hr></div><h1>Reconciliation after a restart</h1><p>Application restarts are another important case.</p><p>Before restart:</p><pre><code><code>Orders:     known
Positions:  known
Exposure:   known</code></code></pre><p>After restart, the application may load whatever was persisted locally.</p><p>But persisted state is not automatically current state.</p><p>A safer startup process is:</p><pre><code><code>Application starts
        &#8595;
Load local state
        &#8595;
Read remote state
        &#8595;
    Compare
        &#8595;
     Repair
        &#8595;
Verify risk
        &#8595;
Allow trading</code></code></pre><p>This changes the meaning of startup.</p><p>Starting the process is not the same thing as starting trading.</p><div><hr></div><h1>Reconciliation after partial fills</h1><p>Partial fills are one possible source of state drift; I wrote separately about <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-partial-fills-trading-bot">Polymarket partial fills</a></strong> and how actual execution can diverge from intended quantity.</p><p>Suppose:</p><pre><code><code>Requested: 100
Filled:     40
Remaining:  60</code></code></pre><p>That is an execution-state problem.</p><p>Then the system needs to establish:</p><pre><code><code>Actual position = ?
Actual exposure = ?
Remaining order = ?
Risk state = ?</code></code></pre><p>The partial-fill problem feeds directly into the reconciliation problem.</p><p>That&#8217;s why I see the two layers as related but distinct:</p><pre><code><code>Partial Fill
     &#8595;
Execution State
     &#8595;
Position State
     &#8595;
Reconciliation</code></code></pre><p>The partial fill tells you what happened to the order.</p><p>Reconciliation tells you whether the rest of the trading system is still consistent with that event.</p><div><hr></div><h1>Health should reflect trading state</h1><p>A dashboard that only shows:</p><pre><code><code>Bot: Running</code></code></pre><p>is not enough.</p><p>A more useful operational state might look like:</p><pre><code><code>SYSTEM: DEGRADED

Market data:         OK
Order stream:        OK
API connectivity:    OK
Position state:      MISMATCH
Last reconciliation: 42s ago
Risk engine:         WARNING
Trading:             PAUSED</code></code></pre><p>That gives the operator a much clearer answer.</p><p>Not:</p><blockquote><p>&#8220;Is the server alive?&#8221;</p></blockquote><p>But:</p><blockquote><p><strong>&#8220;Is the trading system healthy enough to operate?&#8221;</strong></p></blockquote><p>The Control Plane uses explicit states such as:</p><pre><code><code>HEALTHY
DEGRADED
PAUSED
RECOVERING
FAILED</code></code></pre><p>This makes operational state something the rest of the system can reason about.</p><div><hr></div><h1>Reconciliation should be observable</h1><p>Another important design principle is that reconciliation shouldn&#8217;t happen silently.</p><p>The system should produce events such as:</p><pre><code><code>RECONCILIATION_STARTED
STATE_MISMATCH
RECONCILIATION_COMPLETED
TRADING_PAUSED
TRADING_RESUMED</code></code></pre><p>Other useful operational events include:</p><pre><code><code>ORDER_FAILURE
PARTIAL_FILL
MARKET_DATA_STALE
WEBSOCKET_DISCONNECTED
RISK_LIMIT_BREACHED
KILL_SWITCH_TRIGGERED</code></code></pre><p>Those events can then feed:</p><pre><code><code>Dashboard
Logs
Alerts
Webhooks
Monitoring</code></code></pre><p>That turns reconciliation into part of the operational history of the trading system.</p><div><hr></div><h1>The state machine I want</h1><p>The exact implementation is still evolving, but the mental model is:</p><pre><code><code>              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9474;  HEALTHY  &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                    &#9474;
              State becomes
              uncertain
                    &#8595;
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9474; DEGRADED  &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                    &#9474;
                    &#8595;
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9474;  PAUSED   &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                    &#9474;
               Reconcile
                    &#8595;
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9474;RECOVERING &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                    &#9474;
              State verified
                    &#8595;
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9474;  HEALTHY  &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></code></pre><p>This is a much more useful model than simply having:</p><pre><code><code>bot_running = true
</code></code></pre><div><hr></div><h1>What should be verified before resuming?</h1><p>Before automated trading resumes, the system should eventually be able to answer:</p><pre><code><code>[&#10003;] Market data is fresh
[&#10003;] WebSocket is healthy
[&#10003;] Orders are known
[&#10003;] Fills are known
[&#10003;] Positions match
[&#10003;] Exposure is correct
[&#10003;] Risk limits are satisfied
[&#10003;] No critical mismatch remains
[&#10003;] Trading can resume</code></code></pre><p>This creates a clear boundary:</p><pre><code><code>Unverified State
       &#8595;
No New Risk
       &#8595;
Reconciliation
       &#8595;
Verified State
       &#8595;
Risk Check
       &#8595;
Trading Allowed</code></code></pre><p>That&#8217;s the operational behavior I want to build around.</p><div><hr></div><h1>Why the Control Plane exists</h1><p>The goal of the project is not to build another trading strategy.</p><p>It is to build the operational layer around the strategy.</p><pre><code><code>Strategy
    &#8595;
Execution
    &#8595;
State
    &#8595;
Risk
    &#8595;
Monitoring
    &#8595;
Reconciliation
    &#8595;
Recovery</code></code></pre><p>A strategy answers:</p><blockquote><p><strong>What should I trade?</strong></p></blockquote><p>An execution engine answers:</p><blockquote><p><strong>How should I place the order?</strong></p></blockquote><p>A control plane answers:</p><blockquote><p><strong>Can I trust the system enough to keep trading?</strong></p></blockquote><p>That last question is what I&#8217;m exploring.</p><div><hr></div><h1>Where this fits with my other Polymarket projects</h1><p>I&#8217;m approaching several projects as different layers of one larger trading system.</p><h3><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">Polymarket Trading Bot</a></h3><p>Strategy, automated execution, risk controls, and backtesting.</p><h3>Polymarket Execution Verifier</h3><p>Verification across:</p><pre><code><code>Order
 &#8595;
Fill
 &#8595;
Transaction
 &#8595;
Settlement
 &#8595;
Position</code></code></pre><p><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">Polymarket Execution Verifier</a></p><h3>Polymarket Trading Control Plane</h3><p>Monitoring, state, risk, reconciliation, health, alerts, and recovery.</p><p>The architecture becomes:</p><pre><code><code>              Trading Bot
                   &#8595;
               Execution
                   &#8595;
          Execution Verifier
                   &#8595;
             Control Plane
                   &#8595;
       State + Risk + Recovery</code></code></pre><p>The idea isn&#8217;t to add infrastructure for its own sake.</p><p>It&#8217;s to make the system more explicit about what happened and what should happen next.</p><div><hr></div><h1>The project is intentionally early</h1><p>The Control Plane is still in <strong>early development</strong>.</p><p>The first goal is deliberately small:</p><pre><code><code>State
+
Health
+
Reconciliation
+
Risk
+
Operational Control</code></code></pre><p>The project roadmap then extends toward observability, execution timelines, incident replay, portfolio controls, external dashboards, APIs, and integrations.</p><p>I want the foundation to be reliable before adding complexity.</p><div><hr></div><h1>The bigger lesson</h1><p>The most dangerous state in automated trading isn&#8217;t always:</p><pre><code><code>FAILED</code></code></pre><p>Sometimes it&#8217;s:</p><pre><code><code>UNKNOWN</code></code></pre><p>A crashed process is obvious.</p><p>A running process with incorrect state is much harder to notice.</p><p>That&#8217;s why I think a trading system needs a clear concept of:</p><p><strong>trusted state</strong></p><p>and:</p><p><strong>untrusted state</strong></p><p>When the system cannot establish that its view of the account is correct, it should be able to stop taking new risk until it can.</p><div><hr></div><h1>Final takeaway</h1><p>The question isn&#8217;t:</p><blockquote><p><strong>&#8220;Is my Polymarket trading bot running?&#8221;</strong></p></blockquote><p>It&#8217;s:</p><blockquote><p><strong>&#8220;Does my Polymarket trading bot know what the account actually looks like?&#8221;</strong></p></blockquote><p>A WebSocket can disconnect.</p><p>An event can be missed.</p><p>An application can restart.</p><p>An order can partially fill.</p><p>Local state can drift.</p><p>The recovery path should therefore be:</p><pre><code><code>Detect
   &#8595;
Pause
   &#8595;
Reconnect
   &#8595;
Reconcile
   &#8595;
Repair
   &#8595;
Verify
   &#8595;
Risk Check
   &#8595;
Resume</code></code></pre><p>That&#8217;s the core idea behind the <strong>Polymarket Trading Control Plane</strong> I&#8217;m building.</p><p>The strategy can tell the system what it wants to trade.</p><p>The execution layer can attempt to trade it.</p><p>But before the system keeps adding risk, it needs to know whether its state can be trusted.<br><br>Github: <a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">Polymarket Trading Control Plane</a><br></p>]]></content:encoded></item><item><title><![CDATA[Your Polymarket Order Filled. So Why Is Your Position Still Wrong?]]></title><description><![CDATA[A partial fill can change your position, exposure, hedge, and risk. Here's how I think about it in an automated Polymarket trading system.]]></description><link>https://casatrick.substack.com/p/polymarket-partial-fills-trading-bot</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-partial-fills-trading-bot</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Sun, 27 Sep 2026 05:17:04 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F625c7c53-da88-40d2-99ff-3ccae44aa07f_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine your Polymarket trading bot sends an order for 100.</p><p>The market fills 40.</p><p>The order technically worked.</p><p>But your trading system now has a problem.</p><pre><code><code>Requested: 100
Filled:     40
Remaining:  60</code></code></pre><p>What position do you have?</p><p><strong>40.</strong></p><p>Not 100.</p><p>And that difference can affect everything that happens next:</p><ul><li><p>your exposure</p></li><li><p>your hedge</p></li><li><p>your next order</p></li><li><p>your risk calculations</p></li><li><p>your PnL</p></li><li><p>your recovery logic</p></li></ul><p>This is why I think <strong>partial fills are not just an order-management problem</strong>.</p><p>They are a state-management problem.<br><br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;c7ca354c-3b93-4a93-81b7-c8b6f467c59d&quot;,&quot;caption&quot;:&quot;Imagine your Polymarket trading bot sends an order for 100.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Your Polymarket Order Filled. So Why Is Your Position Still Wrong?&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-09-27T05:17:04.654Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/625c7c53-da88-40d2-99ff-3ccae44aa07f_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/polymarket-partial-fills-trading-bot&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:217626479,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h2>An order is an intention. A fill is a fact.</h2><p>This distinction is easy to overlook.</p><p>A strategy may say:</p><pre><code><code>BUY 100</code></code></pre><p>That is an instruction.</p><p>The market may return:</p><pre><code><code>FILLED 40</code></code></pre><p>That is what actually happened.</p><p>Those two numbers should never be treated as interchangeable.</p><p>A useful mental model is:</p><pre><code><code>Strategy Intent
      &#8595;
   Order
      &#8595;
  Execution
      &#8595;
  Actual Fill
      &#8595;
  Position
      &#8595;
  Exposure</code></code></pre><p>The strategy knows what it wanted.</p><p>The execution layer knows what it attempted.</p><p>The account state tells you what actually happened.</p><p>A reliable system has to connect those layers without confusing them.</p><div><hr></div><h1>The simple bot model breaks quickly</h1><p>A basic trading bot can think in terms of:</p><pre><code><code>NOT FILLED
     &#8595;
  FILLED</code></code></pre><p>But real execution needs more state.</p><p>For example:</p><pre><code><code>INTENDED
   &#8595;
SUBMITTED
   &#8595;
ACCEPTED
   &#8595;
PARTIALLY FILLED
   &#8595;
FILLED</code></code></pre><p>And there can be other outcomes:</p><pre><code><code>REJECTED
CANCELLED
FAILED
UNKNOWN
RETRYING</code></code></pre><p>The important part isn&#8217;t having the most complicated state machine.</p><p>It&#8217;s making sure the system can represent what actually happened.</p><div><hr></div><h1>Partial fills change the trade</h1><p>Suppose the strategy wants:</p><pre><code><code>100 contracts</code></code></pre><p>The market gives you:</p><pre><code><code>40 contracts</code></code></pre><p>You now have:</p><pre><code><code>40 actual
60 remaining</code></code></pre><p>That immediately raises new questions.</p><p>Is the remaining 60:</p><ul><li><p>still resting?</p></li><li><p>cancelled?</p></li><li><p>being retried?</p></li><li><p>no longer desirable?</p></li><li><p>impossible to execute at the original price?</p></li></ul><p>And what does the strategy want to do with the 40 that already filled?</p><p>These questions become even more important when the trade is hedged.</p><div><hr></div><h1>Why partial fills matter for hedging</h1><p>Suppose a strategy wants:</p><pre><code><code>Leg 1 = 100
Leg 2 = 100</code></code></pre><p>Now Leg 1 only fills 40.</p><p>The system shouldn&#8217;t automatically behave as though 100 units were acquired.</p><p>The actual state is:</p><pre><code><code>Leg 1 = 40</code></code></pre><p>So a hedge based on actual exposure would look more like:</p><pre><code><code>Leg 1
40 filled
   &#8595;
Hedge requirement
40</code></code></pre><p>rather than:</p><pre><code><code>Requested
100
   &#8595;
Hedge
100</code></code></pre><p>That difference can be significant.</p><p>An automated trading system needs to calculate from <strong>actual fills</strong>, not intentions.</p><div><hr></div><h1>The dangerous case: one leg fills and the other doesn&#8217;t</h1><p>This is especially important for arbitrage and hedged strategies.</p><p>Imagine:</p><pre><code><code>Leg 1 &#8594; 100 filled
Leg 2 &#8594;   0 filled</code></code></pre><p>The strategy expected a balanced position.</p><p>The account now has an unbalanced position.</p><p>The obvious temptation is to immediately retry Leg 2.</p><p>But the market may have changed.</p><p>The spread may have disappeared.</p><p>Liquidity may have changed.</p><p>The original trade may no longer make sense.</p><p>A more deliberate process is:</p><pre><code><code>Leg 1 executed
      &#8595;
Measure actual fill
      &#8595;
Check current market
      &#8595;
Check exposure
      &#8595;
Check risk
      &#8595;
Hedge / cancel / unwind
      &#8595;
Verify final position</code></code></pre><p>This is where execution starts becoming a system-design problem.</p><div><hr></div><h1>Partial fills are also a reconciliation problem</h1><p>There is another layer.</p><p>Suppose your local application believes:</p><pre><code><code>Expected position = +100</code></code></pre><p>Execution records say:</p><pre><code><code>Filled = +40</code></code></pre><p>Remote account state says:</p><pre><code><code>Actual position = +40</code></code></pre><p>Everything is consistent.</p><p>Now imagine the remote account says:</p><pre><code><code>Actual position = +25</code></code></pre><p>The system has a mismatch.</p><p>It now needs to determine why.</p><p>This is where <strong>position reconciliation</strong> becomes important.<br>That problem leads directly into <strong><a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-position-reconciliation">Polymarket position reconciliation</a></strong>, where the question becomes whether local execution state still matches the actual account state.</p><pre><code><code>Local State
     &#8595;
Execution State
     &#8595;
Remote State
     &#8595;
  Compare
     &#8595;
Verified State</code></code></pre><p>The control-plane project I&#8217;m building is designed around exactly this kind of state verification.</p><div><hr></div><h1>A trading bot should know when it does not know</h1><p>One of the most important states in automated trading is:</p><pre><code><code>UNKNOWN</code></code></pre><p>Suppose the bot submits an order.</p><p>The network fails before it gets the final response.</p><p>What happened?</p><p>Maybe the order was rejected.</p><p>Maybe it was accepted.</p><p>Maybe it partially filled.</p><p>Maybe it completely filled.</p><p>The worst response is:</p><blockquote><p>&#8220;I didn&#8217;t get a response, so I&#8217;ll just send the order again.&#8221;</p></blockquote><p>That can create duplicate exposure.</p><p>A safer model is:</p><pre><code><code>UNKNOWN
   &#8595;
Do not blindly retry
   &#8595;
Query / reconcile
   &#8595;
Determine actual state
   &#8595;
Continue according to policy</code></code></pre><p>The system has to be comfortable saying:</p><blockquote><p><strong>I don&#8217;t know yet.</strong></p></blockquote><p>That is much safer than pretending an uncertain state is a known one.</p><div><hr></div><h1>WebSocket reconnects don&#8217;t solve the problem</h1><p>Real-time WebSocket events are important for an automated trading system.</p><p>But reconnecting doesn&#8217;t magically restore everything that happened while disconnected.</p><p>For example:</p><pre><code><code>WebSocket disconnect
        &#8595;
Partial fill occurs
        &#8595;
Event missed
        &#8595;
Connection returns</code></code></pre><p>The connection is healthy again.</p><p>The state may not be.</p><p>That is why a recovery sequence should look more like:</p><pre><code><code>Reconnect
   &#8595;
Reconcile
   &#8595;
Verify orders
   &#8595;
Verify fills
   &#8595;
Verify positions
   &#8595;
Verify exposure
   &#8595;
Resume trading</code></code></pre><p>The principle is simple:</p><blockquote><p><strong>Reconnect is a network event. Recovery is a trading-system operation.</strong></p></blockquote><div><hr></div><h1>Why execution state should be separate from position state</h1><p>One of the architectural choices I keep coming back to is separating:</p><pre><code><code>Order
  &#8595;
Fill
  &#8595;
Position
  &#8595;
Exposure</code></code></pre><p>An order tells you what you requested.</p><p>A fill tells you what executed.</p><p>A position tells you what you hold.</p><p>Exposure tells you what risk that position creates.</p><p>These are related, but they are not the same thing.</p><p>When the system treats them as one object, partial fills and failures become much harder to reason about.</p><p>When they are separate, you can ask:</p><pre><code><code>What did I request?
        &#8595;
What actually filled?
        &#8595;
What position do I have?
        &#8595;
How much am I exposed?</code></code></pre><p>That is a much better foundation for automation.</p><div><hr></div><h1>This is why I am building an Execution Verifier</h1><p>I&#8217;ve been working on a separate <strong>Polymarket Execution Verifier</strong> around this problem.</p><p>The basic idea is:</p><pre><code><code>Order
  &#8595;
Fill
  &#8595;
Transaction
  &#8595;
Settlement
  &#8595;
Position</code></code></pre><p>The system should be able to distinguish between:</p><pre><code><code>KNOWN
UNKNOWN
FAILED
SETTLED
INCONSISTENT</code></code></pre><p>The purpose isn&#8217;t to make the execution layer complicated.</p><p>It is to prevent the trading system from assuming that an order response means the entire trading lifecycle is complete.</p><div><hr></div><h1>And this is where the Control Plane comes in</h1><p>Execution verification answers:</p><blockquote><p><strong>What actually happened?</strong></p></blockquote><p>The Control Plane answers:</p><blockquote><p><strong>Given what happened, should the system continue trading?</strong></p></blockquote><p>The architecture becomes:</p><pre><code><code>Strategy
   &#8595;
Execution
   &#8595;
Execution Verification
   &#8595;
State
   &#8595;
Risk
   &#8595;
Monitoring
   &#8595;
Recovery</code></code></pre><p>That separation is useful because the trading strategy can remain focused on its signal while the infrastructure handles the operational state around it.</p><div><hr></div><h1>What should happen after a partial fill?</h1><p>There is no single answer for every strategy.</p><p>The system may need to:</p><pre><code><code>HEDGE
REPRICE
CANCEL
UNWIND
RETRY
PAUSE</code></code></pre><p>The correct action depends on:</p><ul><li><p>actual filled quantity</p></li><li><p>remaining quantity</p></li><li><p>current market conditions</p></li><li><p>liquidity</p></li><li><p>exposure</p></li><li><p>risk limits</p></li><li><p>strategy rules</p></li></ul><p>That&#8217;s why partial-fill handling belongs close to the execution and risk layers rather than being hidden inside a single strategy function.</p><div><hr></div><h1>The important invariant</h1><p>The way I think about this system can be reduced to one relationship:</p><pre><code><code>Verified Executions
        &#8595;
Actual Position
        &#8595;
Risk Calculation</code></code></pre><p>The downstream system should be using verified state.</p><p>Not:</p><pre><code><code>Strategy Intention
        &#8595;
Assumption
        &#8595;
Risk Calculation</code></code></pre><p>That difference is subtle, but it matters enormously once a bot is operating continuously.</p><div><hr></div><h1>Partial fills should be tested like first-class failures</h1><p>A serious trading system shouldn&#8217;t test only:</p><blockquote><p>&#8220;Did the order fill?&#8221;</p></blockquote><p>It should test:</p><p>ScenarioExpected behaviorFull fillMark execution completePartial fillTrack actual quantityRemaining order openTrack residual quantityRemaining order cancelledRecalculate statePartial hedgeRecalculate exposureUnknown executionReconcile before retryDuplicate eventAvoid double-countingWebSocket reconnectReconcilePosition mismatchBlock tradingSettlement mismatchEscalate</p><p>The difficult part of automated trading often starts after the successful API response.</p><div><hr></div><h1>Where this fits in my current Polymarket work</h1><p>I&#8217;m approaching these projects as different layers of the same trading system.</p><h3>Polymarket Trading Bot</h3><p>Strategy, automated trading, execution, risk controls, and backtesting.</p><h3>Execution Verifier</h3><p>Verifying orders, fills, transactions, settlement, and actual state.</p><h3>Trading Control Plane</h3><p>Monitoring, reconciliation, health, risk, alerts, and recovery.</p><p>Conceptually:</p><pre><code><code>                  POLYMARKET
                       &#9474;
                       &#9660;
                Trading Bot
                       &#9474;
                       &#9660;
                  Execution
                       &#9474;
                       &#9660;
             Execution Verifier
                       &#9474;
                       &#9660;
                 Control Plane
                       &#9474;
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9660;        &#9660;        &#9660;
            State     Risk    Health
              &#9474;        &#9474;        &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                       &#9660;
                  Recovery</code></code></pre><p>The objective isn&#8217;t to add infrastructure for its own sake.</p><p>It&#8217;s to make the system&#8217;s state explicit enough that it can make safer decisions when execution doesn&#8217;t go exactly as planned.</p><div><hr></div><h1>Final thought</h1><p>A partial fill looks like a small detail.</p><p>It isn&#8217;t.</p><p>It can change the:</p><p><strong>position &#8594; exposure &#8594; hedge &#8594; risk &#8594; next trade</strong></p><p>all at once.</p><p>That&#8217;s why I don&#8217;t want an automated trading system to think:</p><blockquote><p>&#8220;The order was submitted, so we&#8217;re done.&#8221;</p></blockquote><p>It should think:</p><pre><code><code>What did we request?
        &#8595;
What actually filled?
        &#8595;
What position do we really have?
        &#8595;
Is our state verified?
        &#8595;
Is it safe to continue?</code></code></pre><p>For automated Polymarket trading, that distinction between <strong>intention, execution, and reality</strong> is where a lot of the interesting engineering begins.</p><div><hr></div><h2>Related work</h2><p><strong>Polymarket Trading Bot</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">https://github.com/casatrickdev/polymarket-trading-bot</a></p><p><strong>Polymarket Execution Verifier</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">https://github.com/casatrickdev/polymarket-execution-verifier</a></p><p><strong>Polymarket Trading Control Plane</strong><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-control-plane">https://github.com/casatrickdev/polymarket-trading-control-plane</a></p><p>More about the broader architecture is in my <a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-trading-bot-architecture">Polymarket Trading Bot Architecture</a> article.</p><p>For execution and backtesting, see <a href="iframe.php?url=https%3A%2F%2Fcasatrick.substack.com%2Fp%2Fpolymarket-bot-backtesting">Polymarket Bot Backtesting</a>.</p><p>&#9888;&#65039; Automated trading involves financial risk. This article discusses trading-system engineering and does not guarantee trading performance or profits.</p>]]></content:encoded></item><item><title><![CDATA[Why a Polymarket Trading Bot Can Be Running and Still Be Unsafe]]></title><description><![CDATA[What happens when a Polymarket trading bot is online but its state, position, risk, or market data can no longer be trusted?]]></description><link>https://casatrick.substack.com/p/polymarket-trading-bot-monitoring</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-trading-bot-monitoring</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Sat, 26 Sep 2026 06:22:25 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F406d0856-231c-42b3-b639-36046fbd6f91_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>That sounds obvious.</p><p>In practice, it is one of the easiest problems to overlook when building an automated trading system.</p><p>A strategy can be correct.</p><p>The API connection can be healthy.</p><p>The process can still be running.</p><p>And the system can still have the wrong view of its positions, orders, exposure, or market state.</p><p>That is the problem behind a project I&#8217;ve been working on: a <strong>Polymarket Trading Control Plane</strong>.</p><p>It is an infrastructure layer around an automated trading system, focused on <strong>state, risk, health, reconciliation, monitoring, and recovery</strong>.</p><p>The idea is simple:</p><blockquote><p>A trading bot should not only know what it wants to trade. It should know whether it is safe to keep trading.</p></blockquote><div><hr></div><h2>The part most trading-bot tutorials don&#8217;t talk about</h2><p>A basic automated trading architecture is easy to understand:</p><pre><code><code>Market Data
    &#8595;
Strategy
    &#8595;
 Order</code></code></pre><p>The strategy receives information, makes a decision, and sends an order.</p><p>That is enough to demonstrate that a bot works.</p><p>But once the system manages real positions continuously, there is another layer of questions:</p><ul><li><p>Is the order actually in the state I think it is?</p></li><li><p>Did the entire order fill?</p></li><li><p>What position do I actually hold?</p></li><li><p>Is my local state current?</p></li><li><p>Is market data fresh?</p></li><li><p>Did I miss an event?</p></li><li><p>Is my exposure still inside the allowed limits?</p></li><li><p>Did the system reconnect after a failure?</p></li><li><p>Should trading resume?</p></li></ul><p>Those questions are not really strategy questions.</p><p>They are <strong>system questions</strong>.</p><p>And when the system is wrong, a correct strategy can make the situation worse by continuing to trade on incorrect information.</p><div><hr></div><h1>A bot can be alive while its state is wrong</h1><p>Consider a simple failure.</p><p>A WebSocket connection drops.</p><p>The application reconnects successfully.</p><p>From the outside, everything looks fine.</p><p>But suppose an execution event was missed during the disconnect.</p><p>Now the local state might say:</p><pre><code><code>Position: +100</code></code></pre><p>while the actual account state is:</p><pre><code><code>Position: +40</code></code></pre><p>The process is healthy.</p><p>The network is healthy.</p><p>The strategy is healthy.</p><p>The state is not.</p><p>That creates a much more dangerous sequence:</p><pre><code><code>WebSocket disconnect
        &#8595;
Missed event
        &#8595;
Local state becomes stale
        &#8595;
Position becomes incorrect
        &#8595;
Risk calculation becomes incorrect
        &#8595;
Strategy keeps trading</code></code></pre><p>This is the type of failure a trading control plane is designed to catch.</p><div><hr></div><h1>Strategy, execution, and control are different layers</h1><p>One of the architectural ideas behind the project is separating three different responsibilities.</p><p>A <strong>strategy</strong> answers:</p><blockquote><p>What should I trade?</p></blockquote><p>An <strong>execution engine</strong> answers:</p><blockquote><p>How should I place the order?</p></blockquote><p>A <strong>control plane</strong> answers:</p><blockquote><p>Can I trust the system enough to keep trading?</p></blockquote><p>Those questions should not be collapsed into one component.</p><p>The broader architecture looks like:</p><pre><code><code>                 STRATEGY
                    &#9474;
                    &#9660;
               Risk Check
                    &#9474;
                    &#9660;
                Execution
                    &#9474;
                    &#9660;
             State / Position
                    &#9474;
                    &#9660;
          Monitoring / Health
                    &#9474;
                    &#9660;
             Reconciliation
                    &#9474;
                    &#9660;
                Recovery</code></code></pre><p>The control layer sits around the trading process rather than trying to become another strategy.<br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;ea920006-a904-4748-922d-6d7f383e5b5b&quot;,&quot;caption&quot;:&quot;A trading bot can start with market data, a strategy, and an order. But reliable execution requires much more than strategy logic.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Building a Production-Grade Polymarket Trading Bot: The Backend Architecture&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-26T05:54:47.668Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1276caad-37ff-476f-b684-7ab4c7fe7f9d_1731x909.png&quot;,&quot;cover_image_alt&quot;:null,&quot;cover_image_crop&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/polymarket-trading-bot-architecture&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:212804892,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:25,&quot;comment_count&quot;:5,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1>What should a Polymarket trading bot monitor?</h1><p>A useful monitoring system needs more than CPU and memory metrics.</p><p>For an automated trading system, the important signals are closer to:</p><h3>Connection health</h3><ul><li><p>WebSocket status</p></li><li><p>API availability</p></li><li><p>order-stream freshness</p></li><li><p>market-data freshness</p></li></ul><h3>Trading state</h3><ul><li><p>open orders</p></li><li><p>executed trades</p></li><li><p>partial fills</p></li><li><p>positions</p></li><li><p>exposure</p></li><li><p>realized PnL</p></li><li><p>unrealized PnL</p></li></ul><h3>System health</h3><ul><li><p>event-processing latency</p></li><li><p>process heartbeat</p></li><li><p>last successful reconciliation</p></li><li><p>degraded subsystems</p></li></ul><p>A simple status screen might eventually look like:</p><pre><code><code>SYSTEM: DEGRADED

Market data:         OK
Order stream:        OK
API connectivity:    OK
Position state:      MISMATCH
Last reconciliation: 42s ago
Risk engine:         WARNING
Trading:             PAUSED</code></code></pre><p>The important distinction is:</p><p><strong>the process being alive is not the same as the trading system being healthy.<br></strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;4ffaba4e-1537-4960-8228-229f8baf7e96&quot;,&quot;caption&quot;:&quot;Speed is supposed to be an advantage.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;I Switched My Polymarket Bot to WebSocket. The Results Were Not What I Expected.&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-06-22T07:16:49.318Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;cover_image_crop&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/i-switched-my-polymarket-bot-to-websocket&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:203052461,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1>Position reconciliation is the safety net</h1><p>Real-time events are useful because trading systems need low-latency updates.</p><p>But events should not automatically be treated as the permanent source of truth.</p><p>Something can always happen between:</p><pre><code><code>Remote State</code></code></pre><p>and:</p><pre><code><code>Local State</code></code></pre><p>So the system needs a way to compare them.</p><p>Conceptually:</p><pre><code><code>Local Orders
      &#9474;
Local Positions
      &#9474;
      &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
             &#9660;
        Remote State
             &#9474;
             &#9660;
        Compare / Repair
             &#9474;
             &#9660;
        Verified State</code></code></pre><p>For example:</p><pre><code><code>POSITION MISMATCH

Market: BTC Up/Down

Local:
+100

Remote:
+40

Difference:
-60

Status:
REQUIRES_RECONCILIATION</code></code></pre><p>Once a mismatch is detected, the system should not simply continue trading because the network connection is back.</p><p>A safer sequence is:</p><pre><code><code>Reconnect
    &#8595;
Reconcile
    &#8595;
Verify Orders
    &#8595;
Verify Positions
    &#8595;
Verify Risk
    &#8595;
Resume Trading</code></code></pre><p>That is the difference between <strong>reconnecting</strong> and <strong>recovering</strong>.</p><div><hr></div><h1>Risk should be independent of the strategy</h1><p>Another important design decision is keeping the risk layer separate from the strategy.</p><p>Imagine several different strategies running on the same trading infrastructure.</p><p>One strategy might be doing arbitrage.</p><p>Another might be following market movements.</p><p>Another might be copying selected traders.</p><p>The risk constraints should not need to be rewritten for every strategy.</p><p>A common control layer can enforce rules such as:</p><pre><code><code>Maximum position
Maximum market exposure
Maximum total exposure
Maximum daily loss
Maximum execution failures
Maximum market-data age</code></code></pre><p>A simplified decision flow becomes:</p><pre><code><code>Risk Check
    &#9474;
    &#9500;&#9472;&#9472; Position limit exceeded? &#9472;&#9472;&#8594; PAUSE
    &#9500;&#9472;&#9472; Daily loss exceeded? &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#8594; KILL
    &#9500;&#9472;&#9472; Data too old? &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#8594; PAUSE
    &#9500;&#9472;&#9472; State mismatch? &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#8594; PAUSE
    &#9492;&#9472;&#9472; Everything OK &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#8594; ALLOW</code></code></pre><p>That makes risk an operational boundary around the strategy rather than part of the strategy itself.</p><div><hr></div><h1>When should an automated bot stop trading?</h1><p>This is one of the questions I think about most when building trading infrastructure.</p><p>A bot should not necessarily continue trading simply because its strategy still sees opportunities.</p><p>There are conditions where the correct trading decision is:</p><blockquote><p><strong>Do nothing.</strong></p></blockquote><p>Examples include:</p><ul><li><p>stale market data</p></li><li><p>position mismatch</p></li><li><p>repeated execution failures</p></li><li><p>unexpected exposure</p></li><li><p>broken connectivity</p></li><li><p>risk-limit breach</p></li><li><p>degraded system health</p></li></ul><p>The project uses explicit operational states such as:</p><pre><code><code>HEALTHY
DEGRADED
PAUSED
RECOVERING
FAILED</code></code></pre><p>This makes operational state something that can be reasoned about instead of a collection of scattered boolean flags.</p><div><hr></div><h1>A kill switch should be boring</h1><p>A kill switch should not be complicated.</p><p>Its job is to stop the system from adding more risk.</p><p>A simple model is:</p><pre><code><code>                 KILL SWITCH
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474;                       &#9474;
     Stop new orders         Exit logic
          &#9474;
          &#9660;
     Freeze strategy
          &#9474;
          &#9660;
      Alert operator</code></code></pre><p>Potential triggers include:</p><ul><li><p>manual operator action</p></li><li><p>daily loss threshold</p></li><li><p>unexpected exposure</p></li><li><p>persistent state mismatch</p></li><li><p>repeated execution failures</p></li><li><p>severe market-data staleness</p></li><li><p>system-health failure</p></li></ul><p>The exact response should depend on the trading system.</p><p>But the important part is that there is an explicit mechanism for saying:</p><blockquote><p><strong>Stop adding risk.</strong></p></blockquote><div><hr></div><h1>Monitoring should produce events, not just dashboards</h1><p>A dashboard is useful for humans.</p><p>A trading system also needs machine-readable events.</p><p>Examples:</p><pre><code><code>STATE_MISMATCH
ORDER_FAILURE
PARTIAL_FILL
MARKET_DATA_STALE
WEBSOCKET_DISCONNECTED
RECONCILIATION_STARTED
RECONCILIATION_COMPLETED
RISK_LIMIT_BREACHED
TRADING_PAUSED
KILL_SWITCH_TRIGGERED</code></code></pre><p>That gives the same operational information multiple destinations:</p><pre><code><code>                    Event
                      &#9474;
        &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
        &#9660;             &#9660;             &#9660;
     Dashboard      Logs         Alerts
                                    &#9474;
                          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                          &#9660;                   &#9660;
                       Telegram           Webhook</code></code></pre><p>It also leaves room for future integrations without changing the underlying event model.</p><div><hr></div><h1>Why I am building this separately from the bot</h1><p>The goal isn&#8217;t to make another giant trading application.</p><p>The goal is to isolate a specific engineering problem:</p><blockquote><p><strong>How do you operate an automated Polymarket trading system when you cannot assume that every event, position, and connection is always correct?</strong></p></blockquote><p>That leads naturally to a small infrastructure layer:</p><pre><code><code>Polymarket
     &#8595;
  Events
     &#8595;
Normalized State
     &#8595;
  Health
     &#8595;
   Risk
     &#8595;
Reconciliation
     &#8595;
  Control</code></code></pre><p>The project is intentionally in early development.</p><p>The first goal is not to build every possible trading feature.</p><p>It is to establish a reliable foundation for state, health, reconciliation, risk, and operational control.<br><br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;5b9bf4b4-ce3d-450f-abe4-4d917408117d&quot;,&quot;caption&quot;:&quot;A lot of people interested in automated Polymarket trading already have some version of a strategy.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Polymarket Trading Bot Development: Build a Custom Trading Bot &quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-09-16T06:48:25.653Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9c0c5b59-466b-45b7-99ae-f6189fe7d452_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;cover_image_crop&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/polymarket-trading-bot-development&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:215946863,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:4,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1>Where this fits with the rest of the trading system</h1><p>I think about automated trading infrastructure as a set of layers.</p><pre><code><code>                 TRADING SYSTEM
                       &#9474;
        &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
        &#9660;              &#9660;              &#9660;
     Strategy       Execution       Data
        &#9474;              &#9474;              &#9474;
        &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                       &#9660;
                CONTROL PLANE
                       &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9660;            &#9660;            &#9660;
        State         Risk        Health
          &#9474;            &#9474;            &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                       &#9660;
                Reconciliation
                       &#9474;
                       &#9660;
                    Recovery</code></code></pre><p>This is also why I don&#8217;t think &#8220;trading bot&#8221; should always mean only the strategy.</p><p>Once a bot becomes a real system, there is a lot of infrastructure around the strategy that determines whether it can operate safely.</p><div><hr></div><h1>What I&#8217;m building next</h1><p>The current roadmap is intentionally incremental.</p><p>The first areas are:</p><p><strong>State monitoring</strong></p><p>Track orders, fills, positions, and system health.</p><p><strong>Reconciliation</strong></p><p>Compare local state with remote state after reconnects, restarts, and suspected event gaps.</p><p><strong>Risk</strong></p><p>Add explicit position, exposure, loss, freshness, and execution-failure controls.</p><p><strong>Operational controls</strong></p><p>Pause, resume, kill switch, reconciliation, and alerts.</p><p><strong>Observability</strong></p><p>Metrics, structured logs, latency tracking, execution timelines, and historical incident replay.</p><p>The longer-term direction is an operational layer sitting between strategy logic and the execution engine.</p><div><hr></div><h1>The bigger lesson</h1><p>The interesting part of automated trading isn&#8217;t always the strategy.</p><p>Sometimes the harder problem is knowing whether the strategy should be allowed to run at all.</p><p>A Polymarket bot can have:</p><ul><li><p>a working strategy</p></li><li><p>a working API connection</p></li><li><p>working code</p></li><li><p>a live process</p></li></ul><p>and still be operating on incorrect information.</p><p>That is why the control problem matters.</p><p>The strategy asks:</p><blockquote><p><strong>What should I trade?</strong></p></blockquote><p>The execution engine asks:</p><blockquote><p><strong>How do I trade it?</strong></p></blockquote><p>The control plane asks:</p><blockquote><p><strong>Can I trust the system enough to keep trading?</strong></p></blockquote><p>That third question is what I&#8217;m exploring with <strong>Polymarket Trading Control Plane</strong>.</p><div><hr></div><h2>Related work</h2><p>This project is part of a broader set of Polymarket trading-system work focused on execution, state, risk, and infrastructure.</p><p>The related projects include:</p><p><strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">Polymarket Trading Bot</a></strong><br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;21577ee2-9084-4f03-b000-43be262e4c6f&quot;,&quot;caption&quot;:&quot;I thought my Polymarket bot strategy worked.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Polymarket Bot Backtesting: I Thought My Strategy Worked Until I Simulated Execution&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:516858575,&quot;name&quot;:&quot;Casatrick&quot;,&quot;bio&quot;:&quot;I build and analyze backend and trading systems for prediction markets. Writing about real-time systems, market data, execution, risk, Rust, Python, and automated trading. https://t.me/casatrick&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-21T13:53:38.781Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0b943f9-0cba-44cf-ba78-3328c4481718_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;cover_image_crop&quot;:null,&quot;canonical_url&quot;:&quot;https://casatrick.substack.com/p/polymarket-bot-backtesting&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:212121235,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:10,&quot;comment_count&quot;:2,&quot;publication_id&quot;:9383612,&quot;publication_name&quot;:&quot;Casatrick&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sdPC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0d873b-6e37-4081-859b-280e2d35d2aa_5000x5000.jpeg&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><strong>Polymarket Execution Verifier</strong><br>Verification across order, fill, transaction, and settlement states.</p><p>The direction is:</p><pre><code><code>Trading Bot
    &#8595;
Execution
    &#8595;
Verification
    &#8595;
Control Plane
    &#8595;
State + Risk + Monitoring + Recovery</code></code></pre><p>The point is not to add complexity for its own sake.</p><p>It is to make the system&#8217;s state more explicit, its failures more visible, and its recovery behavior more deliberate.</p><p>&#9888;&#65039; Automated trading involves financial risk. This project is infrastructure research and does not guarantee profits or trading performance.</p>]]></content:encoded></item><item><title><![CDATA[A Polymarket Fill Isn’t the End: Verifying Execution and Settlement]]></title><description><![CDATA[Building an execution verifier to reconcile orders, fills, transactions, settlement, and uncertain state in automated Polymarket trading systems.]]></description><link>https://casatrick.substack.com/p/polymarket-execution-verification</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-execution-verification</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Thu, 24 Sep 2026 05:47:55 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ce2a407-8d29-4bdf-8bf2-673098287848_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A trading system can tell you that an order was filled.</p><p>That doesn&#8217;t necessarily mean the trade is finished.</p><p>For an automated Polymarket trading system, there are several different things that can happen between <strong>intending to trade</strong> and actually knowing what happened to that trade.</p><p>An order can be submitted but rejected.</p><p>It can be accepted but never matched.</p><p>It can be matched and partially filled.</p><p>A transaction can be submitted but remain pending.</p><p>A local system can believe an execution happened while the remote state says something different.</p><p>And after a failure or reconnect, the system may not know which state is actually correct.</p><p>That creates a problem that is easy to overlook when building a trading bot:</p><blockquote><p><strong>Execution is not a single event. It is a state transition that needs to be verified.</strong></p></blockquote><p>That&#8217;s the problem I&#8217;m exploring with my new project:</p><p><strong>Polymarket Execution Verifier</strong></p><p>The goal is simple: make automated trading systems explicitly verify what happened instead of assuming that an order response means the trade is complete.</p><p><strong>GitHub:</strong> <a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-execution-verifier">[polymarket-execution-verifier]</a></p><div><hr></div><h2>The dangerous assumption: &#8220;the order filled&#8221;</h2><p>Imagine a trading strategy decides to buy.</p><p>The system sends an order.</p><p>The API responds successfully.</p><p>The bot records:</p><pre><code><code>FILLED</code></code></pre><p>From the strategy&#8217;s perspective, everything looks fine.</p><p>But what exactly does <code>FILLED</code> mean?</p><p>Does it mean:</p><ul><li><p>the order was accepted?</p></li><li><p>the order was matched?</p></li><li><p>the entire requested quantity was filled?</p></li><li><p>the fill was observed locally?</p></li><li><p>the transaction was submitted?</p></li><li><p>the transaction was confirmed?</p></li><li><p>the resulting state was reconciled?</p></li><li><p>the position actually exists as expected?</p></li></ul><p>Those are different questions.</p><p>A production trading system needs to distinguish them.</p><div><hr></div><h2>The execution lifecycle</h2><p>I&#8217;m modeling execution as a state machine rather than a single boolean.</p><pre><code><code>INTENDED
   &#8595;
SUBMITTED
   &#8595;
ACCEPTED
   &#8595;
MATCHED
   &#8595;
FILLED
   &#8595;
TX_PENDING
   &#8595;
CONFIRMED
   &#8595;
SETTLED</code></code></pre><p>There are also failure and uncertainty states:</p><pre><code><code>REJECTED
CANCELLED
FAILED
RETRYING
UNKNOWN
INCONSISTENT</code></code></pre><p>The important state here is <strong>UNKNOWN</strong>.</p><p>A lot of trading software treats uncertainty as failure.</p><p>That&#8217;s not always correct.</p><p>If a WebSocket disconnects immediately after an order submission, the system may not know whether the order was accepted, matched, or filled.</p><p>Sending another order immediately could create a duplicate position.</p><p>Treating the trade as failed could also be wrong.</p><p>The correct response is often:</p><blockquote><p><strong>Stop making assumptions and reconcile the state.</strong></p></blockquote><div><hr></div><h2>Why <code>UNKNOWN</code> is a real state</h2><p>Consider this sequence:</p><pre><code><code>Bot
 &#8595;
Submit order
 &#8595;
Exchange accepts order
 &#8595;
Network connection drops
 &#8595;
Bot sees no confirmation</code></code></pre><p>What does the bot know?</p><p>It knows that it attempted the order.</p><p>It does <strong>not</strong> necessarily know that the order failed.</p><p>That distinction matters.</p><p>A na&#239;ve implementation might do:</p><pre><code><code>no response &#8594; retry</code></code></pre><p>A safer implementation can do:</p><pre><code><code>no response
    &#8595;
mark UNKNOWN
    &#8595;
query authoritative state
    &#8595;
reconcile
    &#8595;
determine actual outcome</code></code></pre><p>This pattern is useful far beyond Polymarket.</p><p>It&#8217;s a general distributed-systems problem.</p><p>Whenever two systems communicate over an unreliable network, there can be a gap between <strong>what was attempted</strong> and <strong>what actually happened</strong>.</p><div><hr></div><h2>Off-chain state and on-chain state</h2><p>Polymarket trading systems can also involve multiple sources of truth.</p><p>For example:</p><pre><code><code>                &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                &#9474; CLOB / Orders &#9474;
                &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                        &#9474;
                        &#8595;
                &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                &#9474; Trade / Fill  &#9474;
                &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                        &#9474;
                        &#8595;
                &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                &#9474; Blockchain TX &#9474;
                &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                        &#9474;
                        &#8595;
                &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                &#9474;   Settlement  &#9474;
                &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></code></pre><p>A local trading engine may have its own state as well:</p><pre><code><code>Local state
     +
CLOB state
     +
Fill state
     +
Blockchain state
     &#8595;
Execution verifier</code></code></pre><p>The job of the verifier isn&#8217;t simply to collect more data.</p><p>Its job is to determine whether those states agree.</p><div><hr></div><h2>The reconciliation problem</h2><p>Suppose the local database says:</p><pre><code><code>order_id = 123
status = FILLED
size = 100</code></code></pre><p>But the remote state shows:</p><pre><code><code>order_id = 123
status = PARTIALLY_FILLED
filled = 62</code></code></pre><p>The strategy cannot safely assume that 100 shares were acquired.</p><p>The system needs to surface the discrepancy.</p><p>That&#8217;s why I&#8217;m treating reconciliation as a first-class part of execution infrastructure rather than something hidden inside the strategy code.</p><p>A useful execution record might look conceptually like:</p><pre><code><code>Order
 &#9500;&#9472;&#9472; intended quantity
 &#9500;&#9472;&#9472; submitted quantity
 &#9500;&#9472;&#9472; matched quantity
 &#9500;&#9472;&#9472; filled quantity
 &#9500;&#9472;&#9472; transaction status
 &#9500;&#9472;&#9472; settlement status
 &#9492;&#9472;&#9472; verification status</code></code></pre><p>The strategy should be able to ask:</p><blockquote><p>&#8220;What actually happened?&#8221;</p></blockquote><p>rather than:</p><blockquote><p>&#8220;What did my local process last believe happened?&#8221;</p></blockquote><div><hr></div><h2>Building the Execution Verifier</h2><p>The current project is intentionally small.</p><p>I&#8217;m not trying to build another trading strategy.</p><p>The purpose is to isolate execution verification as its own engineering problem.</p><p>The architecture looks roughly like this:</p><pre><code><code>             POLYMARKET
                 &#9474;
       &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
       &#8595;         &#8595;         &#8595;
     Orders    Fills      TX
       &#9474;         &#9474;         &#9474;
       &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                 &#8595;
        EXECUTION VERIFIER
                 &#9474;
       &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
       &#8595;         &#8595;         &#8595;
     KNOWN     UNKNOWN   FAILED
       &#9474;
       &#8595;
   SETTLED / RECONCILED</code></code></pre><p>The verifier should be able to answer questions such as:</p><ul><li><p>Was the order accepted?</p></li><li><p>Was it actually matched?</p></li><li><p>Was the requested size fully filled?</p></li><li><p>Was it partially filled?</p></li><li><p>Is the transaction pending?</p></li><li><p>Was the transaction confirmed?</p></li><li><p>Does the resulting state match the expected state?</p></li><li><p>Is the execution still uncertain?</p></li><li><p>Does the system need reconciliation before continuing?</p></li></ul><div><hr></div><h2>What happens after a failure?</h2><p>This is where execution verification becomes particularly useful.</p><p>Imagine:</p><pre><code><code>Order submitted
      &#8595;
Connection lost
      &#8595;
Bot restarts
      &#8595;
Local state is incomplete</code></code></pre><p>A na&#239;ve system might immediately resume trading.</p><p>The verifier should instead trigger a recovery process:</p><pre><code><code>START
  &#8595;
Load local execution state
  &#8595;
Query external state
  &#8595;
Compare
  &#8595;
Reconcile
  &#8595;
Resolve UNKNOWN executions
  &#8595;
Rebuild position state
  &#8595;
Verify risk
  &#8595;
Resume trading</code></code></pre><p>This is closely related to the control-plane work I&#8217;ve been building <a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">Polymarket trading bot</a>.</p><p>A reconnect is not the same thing as recovery.</p><p><strong>Recovery means rebuilding confidence in state.</strong></p><div><hr></div><h2>Why this belongs outside the strategy</h2><p>Trading strategies change.</p><p>Execution infrastructure shouldn&#8217;t have to change every time the strategy does.</p><p>For example, the strategy might be:</p><pre><code><code>momentum</code></code></pre><p>or:</p><pre><code><code>mean reversion</code></code></pre><p>or:</p><pre><code><code>arbitrage</code></code></pre><p>The execution problem remains.</p><p>The system still needs to know:</p><pre><code><code>What did we intend to do?
What did we submit?
What was accepted?
What actually filled?
What settled?
What is still uncertain?</code></code></pre><p>Separating those concerns makes the overall architecture easier to reason about.</p><pre><code><code>Strategy
   &#8595;
Order intent
   &#8595;
Execution layer
   &#8595;
Execution verifier
   &#8595;
Reconciled state</code></code></pre><p>The strategy decides <strong>what to trade</strong>.</p><p>The execution layer handles <strong>how to trade</strong>.</p><p>The verifier determines <strong>what actually happened</strong>.</p><div><hr></div><h2>Partial fills are another example</h2><p>Suppose the strategy wants:</p><pre><code><code>100 units</code></code></pre><p>But only:</p><pre><code><code>37 units</code></code></pre><p>are filled.</p><p>Now the system has several possible decisions.</p><p>Should it:</p><ul><li><p>leave the remaining order open?</p></li><li><p>cancel the remainder?</p></li><li><p>submit another order?</p></li><li><p>adjust the strategy?</p></li><li><p>reduce exposure elsewhere?</p></li><li><p>wait for more liquidity?</p></li></ul><p>Those are strategy/risk decisions.</p><p>But before making them, the system needs an accurate answer:</p><blockquote><p><strong>How much was actually filled?</strong></p></blockquote><p>That&#8217;s the verifier&#8217;s job.</p><p>Without reliable execution state, everything downstream is operating on assumptions.</p><div><hr></div><h2>Verification before resuming</h2><p>One design principle I&#8217;m carrying over from the trading control-plane project is:</p><blockquote><p><strong>Don&#8217;t resume trading simply because the process is alive again.</strong></p></blockquote><p>A process can be healthy while its state is wrong.</p><p>After a restart or connection failure, the system should establish confidence in:</p><pre><code><code>orders
fills
positions
transactions
risk
market data</code></code></pre><p>before allowing new execution.</p><p>That creates a much safer lifecycle:</p><pre><code><code>PROCESS RESTART
      &#8595;
STATE RECOVERY
      &#8595;
EXECUTION RECONCILIATION
      &#8595;
POSITION RECONCILIATION
      &#8595;
RISK CHECK
      &#8595;
TRADING ENABLED</code></code></pre><div><hr></div><h2>What I&#8217;m testing next</h2><p>The first version of the project is focused on the state model and verification boundaries.</p><p>The next useful pieces are:</p><ul><li><p>order lifecycle tracking</p></li><li><p>fill reconciliation</p></li><li><p>transaction verification</p></li><li><p>reconnect recovery</p></li><li><p>partial-fill handling</p></li><li><p>idempotent retry behavior</p></li><li><p>persistent execution history</p></li><li><p>structured failure states</p></li><li><p>integration tests</p></li><li><p>simulated disconnects and delayed responses</p></li></ul><p>The testing is particularly important.</p><p>A verifier shouldn&#8217;t only be tested when everything works.</p><p>It should be tested against the ugly cases:</p><pre><code><code>response delayed
response duplicated
WebSocket disconnected
partial fill
order rejected
transaction pending
transaction failed
process restarted
local state stale
remote state changed</code></code></pre><p>Those are the scenarios that reveal whether the system actually understands execution.</p><div><hr></div><h2>This is infrastructure, not a strategy</h2><p>One of the reasons I&#8217;m interested in this project is that it represents a different way of thinking about automated trading systems.</p><p>The strategy gets most of the attention.</p><p>But the strategy is only one layer.</p><p>A production-oriented system also needs:</p><pre><code><code>Market Data
      &#8595;
Event Processing
      &#8595;
   State
      &#8595;
  Strategy
      &#8595;
  Execution
      &#8595;
 Verification
      &#8595;
Reconciliation
      &#8595;
    Risk
      &#8595;
 Monitoring
      &#8595;
  Recovery</code></code></pre><p>Each layer answers a different question.</p><p>And when something goes wrong, the system needs to know <strong>which layer is actually responsible</strong>.</p><p>That&#8217;s the engineering problem I&#8217;m interested in.</p><div><hr></div><h2>The project</h2><p>The Execution Verifier is available on GitHub:</p><p><strong>[polymarket-execution-verifier]</strong></p><p>I&#8217;m building it around a simple principle:</p><blockquote><p><strong>Don&#8217;t let the trading system confuse an attempted execution with a verified execution.</strong></p></blockquote><p>The implementation is evolving around execution state, reconciliation, failure handling, and recovery.</p><p>If you&#8217;re building a Polymarket trading system and dealing with execution-state or reliability problems, I&#8217;d be interested in how you&#8217;re handling them.</p><p><strong>Build the strategy. Verify the execution. Trust the state.</strong></p>]]></content:encoded></item><item><title><![CDATA[Why a Polymarket Trading Bot Needs State Reconciliation]]></title><description><![CDATA[A trading bot can keep running while its local state is already wrong. Here's how I handle stale state, missed events, partial fills, reconnects, and recovery in Polymarket systems.]]></description><link>https://casatrick.substack.com/p/polymarket-trading-bot-state-reconciliation</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-trading-bot-state-reconciliation</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Mon, 21 Sep 2026 13:17:17 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff194745e-5225-4340-8ebb-00b3ed699676_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most people think the difficult part of building a <a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">Polymarket trading bot</a> is placing orders.</p><p>It isn&#8217;t.</p><p>Submitting an order is relatively straightforward.</p><p>The difficult part is knowing whether your bot&#8217;s internal state is still correct after the things that inevitably happen in a real trading system:</p><ul><li><p>a WebSocket disconnects</p></li><li><p>an order is only partially filled</p></li><li><p>a cancellation races with a fill</p></li><li><p>an API response is delayed</p></li><li><p>the process restarts</p></li><li><p>an event is missed</p></li><li><p>the exchange-side state differs from your local state</p></li></ul><p>A bot can keep running while being completely wrong about what it owns, what is open, and how much risk it has.</p><p>That&#8217;s a much more dangerous failure mode than a crashed process.</p><h2>The state problem</h2><p>Imagine a bot submits:</p><pre><code><code>BUY 100 contracts @ 0.57</code></code></pre><p>The local system records:</p><pre><code><code>order_id = 123
status   = OPEN
size     = 100
filled   = 0</code></code></pre><p>Then the market moves.</p><p>The order partially fills:</p><pre><code><code>filled = 40
remaining = 60</code></code></pre><p>Then the WebSocket disconnects.</p><p>Your process reconnects, but the event containing that partial fill was missed.</p><p>Locally, the bot still believes:</p><pre><code><code>filled = 0
remaining = 100</code></code></pre><p>The exchange disagrees.</p><p>Now the strategy has a corrupted view of its position.</p><p>It may:</p><ul><li><p>place another 100-contract order</p></li><li><p>calculate the wrong exposure</p></li><li><p>report the wrong PnL</p></li><li><p>cancel something that is no longer fully open</p></li><li><p>exceed its intended risk limit</p></li></ul><p>Nothing necessarily crashes.</p><p>That is what makes state corruption dangerous.</p><h2>Real-time events are not the same thing as truth</h2><p>Polymarket&#8217;s current CLOB WebSocket exposes separate market and authenticated user channels.</p><p>The user channel provides order lifecycle events such as placement, update, and cancellation, plus trade lifecycle states including <code>MATCHED</code>, <code>MINED</code>, <code>CONFIRMED</code>, <code>RETRYING</code>, and <code>FAILED</code>.</p><p>That is extremely useful for low-latency trading systems.</p><p>But a WebSocket should still be treated as an event-delivery mechanism, not as the only source of truth.</p><p>A production system needs to answer a harder question:</p><blockquote><p><strong>What is the actual current state after something goes wrong?</strong></p></blockquote><p>That requires reconciliation.</p><h2>The architecture I prefer</h2><p>A robust trading system can be thought of as two layers:</p><pre><code><code>                REAL-TIME PATH
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474;   Polymarket CLOB     &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                      &#9474;
                  WebSocket
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474;   Event Processor     &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474;    Local State        &#9474;
          &#9474; orders / fills /      &#9474;
          &#9474; positions / exposure  &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;

              RECONCILIATION PATH
                      &#9474;
          REST / authoritative reads
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474; Reconciliation Engine &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                      &#9474;
               State correction
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474;    Local State        &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></code></pre><p>The real-time path keeps the system fast.</p><p>The reconciliation path keeps the system honest.</p><p>You need both.</p><h2>Step 1: Treat every event as state transition</h2><p>Don&#8217;t let WebSocket messages directly mutate arbitrary application state.</p><p>Instead, convert them into explicit transitions.</p><p>For example:</p><pre><code><code>ORDER_PLACED
     &#8595;
   OPEN
     &#8595;
PARTIALLY_FILLED
     &#8595;
  FILLED</code></code></pre><p>Or:</p><pre><code><code>OPEN
  &#8595;
CANCEL_REQUESTED
  &#8595;
CANCELLED</code></code></pre><p>And failed execution paths need to be represented explicitly too.</p><p>This gives you something that can be tested and replayed.</p><p>It also makes debugging much easier.</p><p>Instead of asking:</p><blockquote><p>&#8220;Why does the bot think it owns 400 contracts?&#8221;</p></blockquote><p>you can ask:</p><blockquote><p>&#8220;Which state transition caused the local position to become 400?&#8221;</p></blockquote><p>That is a much more useful question.</p><h2>Step 2: Make state idempotent</h2><p>Real-time systems eventually see duplicates, retries, reconnects, and repeated information.</p><p>So processing the same event twice should not create two fills.</p><p>Conceptually:</p><pre><code><code>def process_event(event):
    if already_processed(event.id):
        return

    apply_transition(event)
    mark_processed(event.id)</code></code></pre><p>The exact implementation can be more sophisticated, but the principle is important:</p><blockquote><p><strong>Processing the same information twice should not change the final state twice.</strong></p></blockquote><p>This matters especially when a trading system is restarted or replaying buffered events.</p><h2>Step 3: Reconcile after reconnect</h2><p>This is the part many simple bots miss.</p><p>After reconnecting to a WebSocket, don&#8217;t simply resume normal trading.</p><p>First ask:</p><pre><code><code>What do I think is open?
What does the exchange say is open?
What do I think has filled?
What does the exchange say has filled?
What positions do I think I have?
What positions are actually reported?</code></code></pre><p>Then compare.</p><p>For example:</p><pre><code><code>LOCAL                     REMOTE

Order 123: OPEN           Order 123: OPEN
Filled: 0                 Filled: 40

Order 456: FILLED         Order 456: FILLED
Position: +100            Position: +100</code></code></pre><p>The reconciliation engine identifies:</p><pre><code><code>Order 123:
local filled = 0
remote filled = 40

&#8594; local state is stale
&#8594; repair state</code></code></pre><p>Only after reconciliation should the strategy resume normal operation.</p><h2>Step 4: Separate order state from position state</h2><p>These are related, but they are not the same thing.</p><p>An order tells you what you attempted to trade.</p><p>A fill tells you what actually executed.</p><p>A position tells you what exposure you currently have.</p><p>They should not be treated as one variable.</p><p>A useful model is:</p><pre><code><code>Orders
   &#8595;
Fills
   &#8595;
Positions
   &#8595;
Exposure
   &#8595;
Risk</code></code></pre><p>That separation becomes extremely important when partial fills or multiple orders interact.</p><p>For example:</p><pre><code><code>Order A: BUY 100
Order B: BUY 50

A fills 60
B fills 50</code></code></pre><p>Your position is not determined by the original order sizes.</p><p>It is determined by the executed fills.</p><h2>Step 5: Don&#8217;t trust a successful HTTP response too much</h2><p>Another subtle failure mode is assuming that an accepted order response means the entire execution lifecycle is complete.</p><p>Polymarket&#8217;s current CLOB client has already had to adapt to an asynchronous execution pipeline where matched orders can return <code>tradeIDs</code> rather than transaction hashes immediately. The client can then resolve the associated hashes later, or the trades can be followed through the trade API or user WebSocket.</p><p>That&#8217;s an important architecture lesson:</p><blockquote><p><strong>Order acceptance, matching, execution, and settlement are different states.</strong></p></blockquote><p>A production bot should model them separately.</p><h2>Step 6: Recovery should be deliberate</h2><p>Suppose your process dies for five minutes.</p><p>A weak system does this:</p><pre><code><code>restart
&#8595;
connect websocket
&#8595;
resume trading
</code></code></pre><p>A stronger system does:</p><pre><code><code>restart
&#8595;
load persisted state
&#8595;
query current remote state
&#8595;
reconcile orders
&#8595;
reconcile fills
&#8595;
reconcile positions
&#8595;
verify risk limits
&#8595;
resume trading</code></code></pre><p>That extra work is what makes the system recoverable.</p><h2>Why this matters even more during outages</h2><p>This isn&#8217;t hypothetical.</p><p>On September 3, 2026, Polymarket reported an incident involving delayed open-order reads. The incident affected the Predictions Trading API, WebSocket-related systems, markets and position data, and the CLOB WebSocket. Polymarket said the underlying issue involved database replica lag.</p><p>A trading system operating through an incident like that shouldn&#8217;t blindly assume that every local update still represents the current remote state.</p><p>The correct response is not:</p><blockquote><p>&#8220;The API is broken, so keep trading.&#8221;</p></blockquote><p>It is:</p><blockquote><p><strong>Detect degraded data &#8594; stop or reduce risk &#8594; reconcile &#8594; verify state &#8594; resume deliberately.</strong></p></blockquote><h2>The interesting part isn&#8217;t the WebSocket</h2><p>It&#8217;s tempting to think the engineering problem is:</p><blockquote><p>&#8220;How do I connect to the Polymarket WebSocket?&#8221;</p></blockquote><p>That&#8217;s the easy part.</p><p>Current Polymarket tooling already provides market and authenticated user streams, including orderbook updates, order updates, and trade executions.</p><p>The difficult engineering problem is everything that happens around the stream:</p><pre><code><code>connect
subscribe
receive
validate
persist
deduplicate
apply
detect gaps
reconnect
reconcile
repair
resume</code></code></pre><p>That&#8217;s the difference between a bot that works in a demo and a system that can survive real trading conditions.</p><h2>A simple mental model</h2><p>I think about a trading system as having three states:</p><h3>1. Intended state</h3><p>What the strategy wanted to happen.</p><pre><code><code>Buy 100
Cancel order 42
Reduce exposure</code></code></pre><h3>2. Observed state</h3><p>What the event stream tells us happened.</p><pre><code><code>Order placed
40 filled
Cancellation received</code></code></pre><h3>3. Authoritative state</h3><p>What the current exchange-side state says is actually true.</p><pre><code><code>60 remaining
Position = +40
Order still open</code></code></pre><p>A robust system continuously tries to keep these three views consistent.</p><p>When they diverge, <strong>reconciliation is the mechanism that brings them back together.</strong></p><h2>This is the kind of infrastructure that matters</h2><p>The trading strategy gets most of the attention.</p><p>But production trading systems are often won or lost by the less glamorous components:</p><ul><li><p>state management</p></li><li><p>recovery</p></li><li><p>reconciliation</p></li><li><p>execution correctness</p></li><li><p>observability</p></li><li><p>risk controls</p></li><li><p>persistence</p></li><li><p>testing</p></li></ul><p>A strategy can be statistically interesting and still be unusable in production if the infrastructure can&#8217;t reliably answer:</p><blockquote><p><strong>What do I currently own?</strong></p></blockquote><p>That&#8217;s why I increasingly think about Polymarket bot development as a <strong>systems engineering problem</strong>, not simply a strategy implementation problem.</p><p>The order placement code is only one piece.</p><p>The harder system is everything around it.</p><div><hr></div><h3>A practical architecture</h3><p>The minimal version I&#8217;d want for a serious Polymarket trading system looks roughly like this:</p><pre><code><code>             MARKET DATA
                  &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474; WebSocket Layer&#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                  &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474; Event Processor&#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                  &#9474;
        &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
        &#9474; Persisted State    &#9474;
        &#9474; Orders / Fills /   &#9474;
        &#9474; Positions / Risk   &#9474;
        &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                  &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474; Strategy Engine&#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                  &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474; Execution      &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                  &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474; Reconciliation  &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                  &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9660;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9474; Recovery / Risk &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
</code></code></pre><p>That architecture is much closer to what a production trading system actually needs than a script that simply:</p><pre><code><code>receive signal
&#8594; place order
&#8594; repeat
</code></code></pre><h2>Final thought</h2><p>The most dangerous trading-system bug isn&#8217;t always a crash.</p><p>Sometimes it&#8217;s a perfectly healthy process running with an incorrect belief about reality.</p><p>That&#8217;s why state reconciliation deserves to be treated as a first-class part of a Polymarket trading system.</p><p><strong>Fast execution matters.</strong></p><p><strong>Correct state matters more.</strong></p><p>And when the two conflict, the system should know how to stop, verify, repair, and continue.</p><p><em>Note: This article focuses on system architecture and reliability. It intentionally does not disclose proprietary trading logic or strategy parameters.</em></p>]]></content:encoded></item><item><title><![CDATA[AI Agent Wallets Are the Next Infrastructure Layer on Robinhood Chain ]]></title><description><![CDATA[AI agents need more than a private key. This article breaks down wallets, permissions, session keys, policy controls, MCP, transaction simulation, and onchain execution.]]></description><link>https://casatrick.substack.com/p/ai-agent-wallet-robinhood-chain</link><guid isPermaLink="false">https://casatrick.substack.com/p/ai-agent-wallet-robinhood-chain</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Sat, 19 Sep 2026 21:59:32 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2373dd11-2ed0-4681-80bd-605b0d39fd57_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>An AI agent can already read data.</p><p>It can analyze a portfolio.</p><p>It can call APIs.</p><p>The harder problem begins when the agent needs to <strong>act onchain</strong>.</p><p>At that point, a normal wallet architecture starts to look inadequate.</p><p>An autonomous agent needs to know what it is allowed to do, how much capital it can control, which contracts it can interact with, when its permissions expire, how transactions are validated, and how the operator can see or stop what it is doing.</p><p>That is why I think <strong>AI agent wallets</strong> are becoming an important infrastructure category for Robinhood Chain.</p><p>Robinhood Chain is an Ethereum-compatible Layer 2 designed for onchain financial infrastructure and real-world assets. Its documentation says the chain has first-class ERC-4337 account-abstraction support, including programmable wallets, gas sponsorship, batching, and session keys.</p><p>At the same time, Robinhood has moved aggressively toward agentic finance. Its Agentic Trading product connects third-party AI agents through Robinhood&#8217;s MCP and gives those agents access to account information and trading capabilities inside a dedicated account with user-defined capital.</p><p>These are technically different systems, but they point toward the same product question:</p><blockquote><p><strong>What does a wallet need to look like when the user isn&#8217;t the only actor anymore?</strong></p></blockquote><div><hr></div><h1>The Old Wallet Model</h1><p>The traditional architecture is simple:</p><pre><code><code>User
  &#8595;
Wallet
  &#8595;
Signature
  &#8595;
Blockchain</code></code></pre><p>The user decides what to do.</p><p>The user signs.</p><p>The transaction is executed.</p><p>That model works because the human is the decision-maker and the signing authority.</p><p>An AI agent changes that relationship.</p><p>Now the architecture starts looking like:</p><pre><code><code>User
  &#8595;
AI Agent
  &#8595;
Decision
  &#8595;
Wallet
  &#8595;
Blockchain</code></code></pre><p>The problem is that the AI should not automatically inherit everything the user owns.</p><p>Giving an AI agent a master private key is a very different security model from giving it a limited set of permissions.</p><p>A better architecture is:</p><pre><code><code>AI Agent
   &#8595;
Action Request
   &#8595;
Policy
   &#8595;
Risk
   &#8595;
Permission
   &#8595;
Wallet / Signer
   &#8595;
Robinhood Chain</code></code></pre><p>That separation is the foundation of an agent wallet.</p><div><hr></div><h1>What a Client Actually Wants</h1><p>A client rarely asks for:</p><blockquote><p>&#8220;Build me an ERC-4337 wallet.&#8221;</p></blockquote><p>The real requirement sounds more like:</p><blockquote><p>&#8220;I want my AI agent to manage positions, interact with contracts, and perform transactions without giving it unrestricted access to my treasury.&#8221;</p></blockquote><p>That requirement expands into several engineering problems.</p><p>The client needs:</p><p><strong>controlled permissions</strong></p><p><strong>spending limits</strong></p><p><strong>session expiration</strong></p><p><strong>allowed contracts</strong></p><p><strong>allowed assets</strong></p><p><strong>transaction simulation</strong></p><p><strong>approval workflows</strong></p><p><strong>audit logs</strong></p><p><strong>monitoring</strong></p><p><strong>emergency controls</strong></p><p>The wallet is only the center of that system.</p><div><hr></div><h1>Why Robinhood Chain Is Interesting for This</h1><p>Robinhood Chain is EVM compatible, and Robinhood explicitly documents ERC-4337 account abstraction as part of the chain&#8217;s architecture. Its documentation highlights programmable wallets, gas sponsorship, batching, and session keys.</p><p>That matters because agent wallets need more flexibility than a simple externally owned account.</p><p>Imagine a user creates an agent with:</p><pre><code><code>Allowed Tokens:
AAPL Token
NVDA Token
USDG

Maximum Trade:
$500

Daily Spend:
$2,000

Allowed Contracts:
Approved DEX only

Session:
24 hours</code></code></pre><p>The agent can operate.</p><p>But it operates <strong>inside a box</strong>.</p><p>That&#8217;s a much more useful model for autonomous finance.</p><div><hr></div><h1>Session Keys Change the Permission Model</h1><p>One of the most interesting primitives here is the session key.</p><p>Instead of:</p><pre><code><code>Main Wallet
     &#8595;
Permanent Private Key
     &#8595;
Unlimited Authority</code></code></pre><p>you can think in terms of:</p><pre><code><code>Main Account
     &#8595;
Temporary Session
     &#8595;
Scoped Permission
     &#8595;
AI Agent</code></code></pre><p>A session can define:</p><ul><li><p>expiration</p></li><li><p>allowed contracts</p></li><li><p>allowed operations</p></li><li><p>spending limits</p></li><li><p>asset restrictions</p></li><li><p>strategy scope</p></li></ul><p>For example:</p><pre><code><code>Agent Session

Expires:
18:00 UTC

Can:
Swap approved assets

Cannot:
Transfer treasury funds

Maximum:
$500 / transaction

Daily:
$2,000</code></code></pre><p>Robinhood Chain explicitly lists session-key support as part of its account-abstraction functionality.</p><p>For a client building an autonomous application, this is a much more interesting primitive than simply handing a server a private key.</p><div><hr></div><h1>The Policy Engine Is More Important Than the Wallet</h1><p>This is probably the biggest architectural insight.</p><p>The wallet signs.</p><p>The <strong>policy engine determines what the wallet is allowed to sign</strong>.</p><p>For example:</p><pre><code><code>AI says:

"Swap $1,500 of Asset A."</code></code></pre><p>The policy layer checks:</p><pre><code><code>Maximum trade = $500</code></code></pre><p>Result:</p><pre><code><code>REJECT</code></code></pre><p>The model cannot negotiate with the policy.</p><p>A simple architecture:</p><pre><code><code>                  AI Agent
                      &#9474;
                      &#9660;
                Action Request
                      &#9474;
                      &#9660;
                 Policy Engine
                      &#9474;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#9660;           &#9660;           &#9660;
      Asset Rule   Spend Rule   Contract Rule
          &#9474;           &#9474;           &#9474;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                      &#9660;
                  Risk Check
                      &#9474;
                      &#9660;
                  Permission
                      &#9474;
                      &#9660;
                     Sign</code></code></pre><p>This gives the client a predictable security boundary.</p><div><hr></div><h1>Read Access and Write Access Should Be Different</h1><p>A strong design separates <strong>observation</strong> from <strong>action</strong>.</p><p>Read operations:</p><pre><code><code>getPortfolio()
getBalance()
getPrice()
getPosition()
getHistory()</code></code></pre><p>Write operations:</p><pre><code><code>swap()
transfer()
deposit()
withdraw()
borrow()</code></code></pre><p>The AI may be allowed to read a large amount of information.</p><p>Its write capabilities should be much narrower.</p><p>That makes the permission model easier to understand and easier to audit.</p><p>The pattern is:</p><pre><code><code>READ
&#8594; Broad

WRITE
&#8594; Narrow

SIGN
&#8594; Strictly controlled</code></code></pre><p>That&#8217;s especially relevant for financial agents.</p><div><hr></div><h1>MCP Becomes the Tool Interface</h1><p>The agent still needs a way to interact with the application.</p><p>That is where MCP becomes useful.</p><p>Robinhood&#8217;s own Agentic Trading product uses a Trading MCP to let compatible AI agents access Robinhood account information and supported trading actions. Robinhood&#8217;s current support documentation lists portfolio/account queries, market-data analysis, portfolio rebalancing, and order placement among the supported use cases.</p><p>For an onchain agent, the same architectural idea can be applied to wallet and financial tools:</p><pre><code><code>getPortfolio()
getBalance()
getToken()
getPrice()
getQuote()
checkPolicy()
simulateTransaction()
prepareTransaction()
getTransactionStatus()</code></code></pre><p>The AI doesn&#8217;t need to know how the backend works.</p><p>It needs to know:</p><pre><code><code>Tool
Input
Output</code></code></pre><p>That separation makes the agent easier to swap, upgrade, and test.</p><div><hr></div><h1>The Agent Should Never Construct Arbitrary Transactions</h1><p>A tempting architecture is:</p><pre><code><code>LLM
 &#8595;
Raw Contract Call
 &#8595;
Signer
 &#8595;
Chain</code></code></pre><p>I wouldn&#8217;t build it that way.</p><p>Instead:</p><pre><code><code>LLM
 &#8595;
Intent
 &#8595;
Tool
 &#8595;
Validated Parameters
 &#8595;
Policy
 &#8595;
Simulation
 &#8595;
Signer
 &#8595;
Chain</code></code></pre><p>For example, the model might say:</p><blockquote><p>&#8220;Rebalance the portfolio to reduce Asset A to 15%.&#8221;</p></blockquote><p>The application turns that into a structured action.</p><pre><code><code>{
  "action": "rebalance",
  "asset": "0x...",
  "targetWeight": 0.15
}</code></code></pre><p>Then the rest of the system performs deterministic checks.</p><p>The AI proposes.</p><p>The infrastructure enforces.</p><div><hr></div><h1>Transaction Simulation Should Be Mandatory</h1><p>Before a financial agent signs anything, I would run a simulation whenever the execution stack supports it.</p><p>The flow becomes:</p><pre><code><code>AI Proposal
     &#8595;
Build Transaction
     &#8595;
Simulate
     &#8595;
Policy Check
     &#8595;
Risk Check
     &#8595;
Approval
     &#8595;
   Sign
     &#8595;
  Submit</code></code></pre><p>Simulation can help catch:</p><ul><li><p>invalid parameters</p></li><li><p>insufficient balances</p></li><li><p>contract reverts</p></li><li><p>unexpected execution paths</p></li><li><p>incompatible calls</p></li></ul><p>The purpose isn&#8217;t to guarantee success.</p><p>It&#8217;s to reduce the number of obviously unsafe or invalid transactions that reach the signer.</p><div><hr></div><h1>Spending Limits Need Their Own State</h1><p>A limit like:</p><pre><code><code>Daily spend = $2,000</code></code></pre><p>isn&#8217;t just a configuration value.</p><p>The system has to track actual usage.</p><p>For example:</p><pre><code><code>09:12    Trade    $250
10:41    Trade    $400
13:20    Trade    $175

Daily total:       $825
Remaining:       $1,175</code></code></pre><p>The counter should live outside the model.</p><p>The AI cannot decide:</p><blockquote><p>&#8220;I have permission to spend another $2,000.&#8221;</p></blockquote><p>The policy service knows the actual remaining allowance.</p><div><hr></div><h1>Human Approval Is Still a Product Feature</h1><p>Not every client needs full autonomy.</p><p>A useful agent wallet should support several modes.</p><h3>Advisory</h3><pre><code><code>AI
 &#8595;
Recommendation</code></code></pre><h3>Approval-based</h3><pre><code><code>AI
 &#8595;
Transaction Proposal
 &#8595;
Human Approval</code></code></pre><h3>Limited autonomy</h3><pre><code><code>AI
 &#8595;
Policy
 &#8595;
Risk
 &#8595;
Execute</code></code></pre><h3>Highly autonomous</h3><pre><code><code>AI
 &#8595;
Policy
 &#8595;
Risk
 &#8595;
Session Permission
 &#8595;
Execute</code></code></pre><p>This lets a product gradually increase automation without completely changing its architecture.</p><p>Robinhood&#8217;s Agentic Trading product itself uses a dedicated agentic account and capital allocation model, allowing users to reserve funds for the agent and disconnect it when needed.</p><div><hr></div><h1>Agent Wallets Are Not Only About Trading</h1><p>This is where the opportunity gets much bigger.</p><p>A wallet controlled through scoped agent permissions can be used for:</p><p><strong>RWA applications</strong></p><p>An agent manages tokenized-asset positions.</p><p><strong>DeFi</strong></p><p>An agent manages lending, liquidity, or other positions within predefined policies.</p><p><strong>Treasury automation</strong></p><p>An agent handles routine treasury operations.</p><p><strong>Portfolio management</strong></p><p>An agent proposes or executes rebalancing.</p><p><strong>Machine payments</strong></p><p>An agent pays for another service or API.</p><p><strong>Autonomous services</strong></p><p>An agent earns and spends assets without a human manually signing every transaction.</p><p>This last category is already appearing in the public Robinhood Chain ecosystem.</p><p>For example, current open-source projects are experimenting with MCP servers that expose trading/data capabilities, agent wallets, and x402-style machine payments on Robinhood Chain.</p><p>That is a meaningful signal.</p><p>The ecosystem is beginning to treat the wallet as an <strong>agent identity and execution layer</strong>, not just a place to store tokens.</p><div><hr></div><h1>The x402 / Machine-Payment Angle</h1><p>This may eventually become one of the more interesting use cases.</p><p>An autonomous agent might need to:</p><pre><code><code>Discover Service
      &#8595;
Request Service
      &#8595;
Receive Price
      &#8595;
     Pay
      &#8595;
Receive Result</code></code></pre><p>Instead of:</p><pre><code><code>Human
 &#8595;
Credit Card
 &#8595;
Service</code></code></pre><p>The agent becomes an economic actor.</p><p>Current open-source Robinhood Chain projects already experiment with AI agents paying for services or compute using USDG and x402-style flows.</p><p>That creates possible infrastructure around:</p><ul><li><p>machine wallets</p></li><li><p>payment policies</p></li><li><p>merchant discovery</p></li><li><p>service payments</p></li><li><p>agent balances</p></li><li><p>usage accounting</p></li></ul><p>This is separate from trading and therefore a particularly interesting area for developers who don&#8217;t want to build another trading bot.</p><div><hr></div><h1>Observability Becomes Essential</h1><p>An autonomous wallet shouldn&#8217;t be a black box.</p><p>The operator needs to see:</p><pre><code><code>Agent Status
Wallet Balance
Active Session
Daily Spend
Pending Transactions
Confirmed Transactions
Rejected Actions
Policy Violations</code></code></pre><p>But I&#8217;d go deeper than a dashboard.</p><p>Store the decision trail:</p><pre><code><code>User Request
&#8595;
Agent Decision
&#8595;
Tool Calls
&#8595;
Data Used
&#8595;
Policy Result
&#8595;
Risk Result
&#8595;
Simulation Result
&#8595;
Approval
&#8595;
Transaction
&#8595;
Execution</code></code></pre><p>Then the operator can answer:</p><blockquote><p>Why did the agent do this?</p></blockquote><p>That becomes increasingly important as agents become more autonomous.</p><p>Robinhood&#8217;s Agentic Trading product already emphasizes a real-time activity feed and performance visibility for agent actions, which is a useful signal that observability is part of the product experience rather than an optional engineering extra.</p><div><hr></div><h1>A Practical Architecture</h1><p>If I were building an AI agent wallet for a client today, I&#8217;d separate the system into six layers.</p><pre><code><code>                  AI Agent
                      &#9474;
                      &#9660;
                 Tool / MCP
                      &#9474;
                      &#9660;
             Data + Portfolio
                      &#9474;
                      &#9660;
              Policy + Risk
                      &#9474;
                      &#9660;
          Smart Account / Session
                      &#9474;
                      &#9660;
            Signer / Execution
                      &#9474;
                      &#9660;
               Robinhood Chain</code></code></pre><p>And around the entire system:</p><pre><code><code>              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9474;    Observability    &#9474;
              &#9474;Logs / Audit / Alerts&#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></code></pre><p>Every layer has a separate responsibility.</p><div><hr></div><h1>What I Would Build First</h1><p>I wouldn&#8217;t start with a fully autonomous financial agent.</p><p>I&#8217;d start with a controlled wallet infrastructure.</p><h3>Phase 1</h3><pre><code><code>Smart Account
+
Agent Identity
+
Read-only Tools
+
Policy Engine</code></code></pre><p>The agent can inspect the portfolio but not execute.</p><h3>Phase 2</h3><p>Add:</p><pre><code><code>Transaction Simulation
+
Limited Write Permissions
+
Session Keys
+
Spend Limits</code></code></pre><p>Now the agent can execute specific actions.</p><h3>Phase 3</h3><p>Add:</p><pre><code><code>MCP
+
AI Orchestration
+
Monitoring
+
Audit Trail
+
Automated Strategies</code></code></pre><p>Now you have a complete agent platform.</p><h3>Phase 4</h3><p>Expand into:</p><pre><code><code>RWA
DeFi
Trading
Machine Payments
Treasury</code></code></pre><p>The same wallet infrastructure can support all of them.</p><div><hr></div><h1>What a Real Product Could Look Like</h1><p>Imagine an AI agent dashboard:</p><pre><code><code>AGENT WALLET

Status              ACTIVE
Balance             $8,420
Today's Spend         $620
Daily Limit         $2,000

Permissions
&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;
AAPL Token          &#10003;
USDG                &#10003;
Approved DEX        &#10003;

Session
&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;
Expires             16h 24m

Recent Actions
&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;
Portfolio read       &#10003;
Quote request        &#10003;
Trade proposal       &#10003;
Simulation            &#10003;
Transaction           &#10003;</code></code></pre><p>The user doesn&#8217;t have to understand ERC-4337.</p><p>They just see:</p><p><strong>what the agent can do, what it has done, and how much authority it has.</strong></p><p>That is what good infrastructure should accomplish.</p><div><hr></div><h1>What Clients Are Actually Buying</h1><p>A client asking for an AI agent wallet isn&#8217;t really buying:</p><blockquote><p><strong>&#8220;an AI wallet.&#8221;</strong></p></blockquote><p>They&#8217;re buying a system that connects:</p><pre><code><code>AI
+
Tools
+
Data
+
Permissions
+
Risk
+
Wallet
+
Signing
+
Execution
+
Monitoring</code></code></pre><p>The AI model is only one component.</p><p>The expensive engineering is usually in the boundaries between those components.</p><p>That&#8217;s where custom development becomes valuable.</p><p>A team might already have the AI model.</p><p>Another team might already have the frontend.</p><p>What they may not have is the <strong>onchain agent infrastructure connecting the two safely</strong>.</p><div><hr></div><h1>The Bigger Opportunity on Robinhood Chain</h1><p>Robinhood Chain already provides important primitives for this direction: EVM compatibility, ERC-4337 account abstraction, programmable wallets, gas sponsorship, batching, and session keys.</p><p>Robinhood&#8217;s own agentic products demonstrate that the company is actively designing around AI agents, controlled capital, MCP, and automated financial actions.</p><p>And the public developer ecosystem is beginning to build around MCP servers, agent wallets, autonomous execution, and machine payments on the chain.</p><p>That creates a different development opportunity from the current wave of meme-token and trading-bot tooling.</p><p>The question becomes:</p><blockquote><p><strong>What does financial infrastructure look like when the user can delegate actions to software?</strong></p></blockquote><p>The answer isn&#8217;t simply &#8220;give the AI a private key.&#8221;</p><p>It&#8217;s:</p><pre><code><code>Agent
 &#8595;
Tools
 &#8595;
Policy
 &#8595;
Risk
 &#8595;
Permissions
 &#8595;
Wallet
 &#8595;
Execution
 &#8595;
Audit</code></code></pre><p>That architecture can support much more than trading.</p><p>It can support <strong>RWA applications, DeFi automation, financial agents, treasury systems, portfolio managers, and machine-to-machine payments</strong>.</p><p>And that&#8217;s the direction I&#8217;d watch closely as Robinhood Chain&#8217;s developer ecosystem matures.</p><h2>Building an AI Agent on Robinhood Chain?</h2><p>The interesting engineering work is around the system surrounding the model:</p><p><strong>agent tools, wallet architecture, session permissions, policy engines, transaction simulation, controlled signing, execution, and observability.</strong></p><p>That&#8217;s the infrastructure layer I would build.</p>]]></content:encoded></item><item><title><![CDATA[The Pons Sniper Bot Playbook: Why Speed Alone Loses Money on Robinhood Chain]]></title><description><![CDATA[Pons V2 charges a 99% tax on same-second buys - and it decays to near-zero by second two. Here's the execution architecture that prices that in instead of just racing the mempool.]]></description><link>https://casatrick.substack.com/p/pons-sniper-bot-robinhood-chain</link><guid isPermaLink="false">https://casatrick.substack.com/p/pons-sniper-bot-robinhood-chain</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Fri, 18 Sep 2026 20:07:49 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8428f4f5-6c35-405f-83d6-985efa9480db_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every &#8220;Robinhood Chain sniper bot&#8221; post published in the last two months describes the same thing: watch the mempool, catch the pool-creation event, buy in the same block. That&#8217;s pump.fun-era thinking, and it&#8217;s a losing playbook on Pons specifically. Pons V2 has a protocol-level anti-snipe tax that can take <strong>99% of a same-second buy</strong> before you ever get to slippage or gas. Understanding that tax curve - not raw latency - is the actual edge here.</p><p>This post is a technical walkthrough of how Pons V2 launches on Robinhood Chain actually work, where the real execution edge lives, and how we structure the bot pipeline at Casatrick to trade it correctly.</p><h2>What Robinhood Chain actually is</h2><p>Robinhood Chain is an Ethereum Layer 2 built on Arbitrum&#8217;s Orbit technology, inheriting Ethereum&#8217;s security while processing transactions faster and more cheaply. It launched as a permissionless Layer 2 for financial services and tokenized real-world assets, built to institutional standards with day-one integrations from Uniswap, Chainlink, Alchemy, and BitGo.</p><p>The pitch was tokenized equities. The reality, at least in its first two months, has been different: Robinhood Chain quickly became one of crypto&#8217;s busiest new networks by transaction count, but tokenized real-world assets have accounted for only a small fraction of activity, with memecoins and stablecoins dominating volume instead. That&#8217;s the environment Pons operates in, and it&#8217;s why a launchpad bot on this chain is a real, ongoing business rather than a novelty.</p><h2>Pons: the dominant launchpad on RHC</h2><p>Pons has emerged as the central launchpad infrastructure on Robinhood Chain, at times driving over half of the chain&#8217;s total activity and generating millions of dollars in daily fees. There are two generations you need to treat as separate protocols, not versions of the same thing:</p><ul><li><p><strong>Pons V1</strong> - a fixed-supply ERC-20 minted straight into a Uniswap V3 position at launch. No curve. No snipe tax. If your bot logic assumes V1, it will misfire badly against V2 launches, because V2 doesn&#8217;t create a tradable pool at launch at all.</p></li><li><p><strong>Pons V2</strong> - introduced bonding curves and support for custom quote assets, including tokenized stocks, differentiating it from a simple meme-coin platform. This is the version launching now, and the version this article is about.</p></li></ul><p>A V2 launch mints a fixed 1,000,000,000-token supply directly into a per-token bonding curve contract. There is no pool yet - trades execute against the curve itself. Once the curve takes in its graduation threshold (4.2 ETH for a native-quoted launch, or a per-asset threshold for an ERC-20 quote), the curve is swept and a Uniswap v4 pool is seeded behind a Pons-owned hook, with the liquidity position <strong>permanently locked</strong>. The supply split is fixed by protocol design regardless of quote asset: roughly five-sevenths of supply sells on the curve, and the remaining two-sevenths gets swept at graduation - most of that seeding the locked v4 position, with a smaller slice permanently locked in a separate contract.</p><p>Quote assets aren&#8217;t limited to ETH. Pons V2 supports USDG, cbBTC, and a growing list of tokenized stocks and ETFs - TSLA, NVDA, AAPL, GME, SPY, and dozens more - each with its own graduation threshold denominated in that asset&#8217;s own decimals. A launch quoted in NVDA instead of ETH is a materially different pricing problem for a bot, which we&#8217;ll get to.</p><p>The lifecycle, end to end:</p><pre><code><code>TokenLaunched
   &#8595;
Bonding curve (CurveBuy / CurveSell)
   &#8595;
CurveCompleted (threshold hit)
   &#8595;
LaunchSwept
   &#8595;
PoolGraduated &#8594; Uniswap v4 (behind PonsV2MemeHook)</code></code></pre><h2>The part every generic bot gets wrong: the snipe-tax decay curve</h2><p>This is the single most important mechanic in this article, and it&#8217;s the reason a naive &#8220;first block&#8221; sniper loses money on Pons where it might print on a pool with no curve at all.</p><p>Pons charges a fast-decaying tax on buys inside the launch window, computed on-chain, not something you can route around with a private RPC or a higher tip:</p><pre><code><code>snipeTaxBps(elapsed) = snipeTaxStartBps &gt;&gt; ((elapsed * 14) / snipeTaxSeconds)</code></code></pre><p><code>elapsed</code> is seconds since the launch transaction, integer division throughout, and the tax hits zero once <code>elapsed &gt;= snipeTaxSeconds</code>. At the factory&#8217;s current settings (<code>snipeTaxStartBps = 9900</code>, <code>snipeTaxSeconds = 3</code>), that resolves to:</p><p>Second after launch Effective snipe tax 0 (same block/second as launch) <strong>99.00%</strong> 1 <strong>6.18%</strong> 2 <strong>0.19%</strong> 3+ 0%</p><p>A bot that wins the race to be first into the block is walking straight into a 99% haircut on top of the normal 1% curve fee and whatever creator tax is set. The actual optimal entry, in most cases, is the <em>second</em> window - a couple of seconds after launch, where the tax has decayed to near-zero but you&#8217;re still meaningfully ahead of manual traders. That is a fundamentally different targeting problem than &#8220;fastest possible transaction,&#8221; and it&#8217;s why a bot built for Pons has to price in tax decay as a first-class variable, not an edge case.</p><p>There&#8217;s a second, narrower path: creators can pre-declare exempt wallets at launch (<code>SnipeTaxExempted</code>), which zeroes the tax for those addresses from block one. That&#8217;s not something a bot can force its way into - it&#8217;s a relationship/allowlist mechanic, which is one of the reasons a serious trading operation benefits from actual infrastructure and track record rather than an anonymous bundler.</p><p>Both <code>snipeTaxStartBps</code> and <code>snipeTaxSeconds</code> are owner-mutable, so a bot that hardcodes these constants will silently mis-price every launch the moment the factory&#8217;s settings change. They need to be read live off the factory, not assumed.</p><h2>Stock-quoted curves add a second pricing dimension</h2><p>When a launch is quoted in NVDA or TSLA instead of ETH, your bot isn&#8217;t just tracking curve state - it&#8217;s tracking two moving prices at once: the bonding curve&#8217;s internal price <em>and</em> the market price of the tokenized-equity quote asset. Robinhood Chain&#8217;s stock tokens carry Chainlink oracle feeds specifically so their onchain price tracks the underlying equity. A bot that sizes a buy without pulling that oracle price will misjudge real-dollar exposure and slippage bounds on every equity-quoted launch - a mistake that&#8217;s invisible until the stock itself moves 2% mid-trade.</p><h2>The second sniping surface nobody talks about: graduation</h2><p>Graduation itself is permissionless and runs in two separate transactions: <code>graduate()</code> sweeps the curve and halts trading, then a separate <code>createGraduatedPool()</code> call actually mints the Uniswap v4 position and unlocks trading on the pool. In practice, keeper bots race to trigger this second call the moment a curve crosses threshold - which means there&#8217;s a second, distinct execution window (the first pool-trade after graduation) that has nothing to do with the original launch snipe. Most &#8220;sniper bot&#8221; content ignores this entirely because it&#8217;s written from a Solana pump.fun mental model, where graduation isn&#8217;t a separate racable transaction.</p><h2>Architecture: the pipeline we actually run</h2><p>At Casatrick, our trading infrastructure follows the same shape whether we&#8217;re building copy-trading or launch-sniping logic, because the correctness problems are the same problem:</p><p><strong>Wallet/Event Detection &#8594; State Classification &#8594; Execution Math &#8594; Filtering &#8594; Risk &#8594; Execution &#8594; Confirmation</strong></p><p>Applied to Pons specifically:</p><ol><li><p><strong>Event detection</strong> - subscribe to <code>TokenLaunched</code> on the factory and <code>CurveBuy</code>/<code>CurveSell</code>/<code>SnipeTaxCharged</code> on the curve layer. Curves are one contract per token, so this is a topic-based scan across the whole network, not a fixed address.</p></li><li><p><strong>State classification</strong> - before anything else, determine which protocol generation you&#8217;re looking at (V1 vs V2) and which lifecycle phase the token is in (curve-trading, swept, graduated). A bot that can&#8217;t tell these apart will send transactions against contracts that no longer do what it expects.</p></li><li><p><strong>Execution math</strong> - compute the deterministic curve quote for the intended buy size, then apply the <em>current</em> live snipe-tax rate and base fee read off the factory, not hardcoded constants. For equity-quoted launches, pull the oracle price for the quote asset in the same step.</p></li><li><p><strong>Filtering</strong> - reject launches where the quote-asset approval looks stale, where creator tax is at the factory&#8217;s cap, or where the launch metadata (pulled from calldata, since Pons has no separate metadata event) looks templated/spam.</p></li><li><p><strong>Risk</strong> - position sizing bounded by curve depth and threshold remaining, slippage bounds derived from the actual curve formula rather than a flat percentage, and  critically - a policy for <em>when</em> to enter relative to the tax-decay curve rather than always entering at t=0.</p></li><li><p><strong>Execution</strong> - signed and submitted through an isolated signer, with the transaction&#8217;s <code>minTokensOut</code> set from the same curve math used for filtering, so a stale quote fails closed instead of executing at a worse price.</p></li><li><p><strong>Confirmation</strong> - verify the trade against emitted <code>CurveBuy</code> data (not just transaction success), since a revert-free transaction and a fill at your expected price aren&#8217;t the same thing on a curve with a dynamic tax component.</p></li></ol><h2>Verifying you&#8217;re actually trading the real thing</h2><p>Two trust checks are worth building into any Pons tooling, because they&#8217;re also good client-facing proof points:</p><ul><li><p><strong>Locked liquidity, twice.</strong> A graduated Pons token has its Uniswap v4 position held in a dedicated locker contract <em>and</em> a separate slice of supply locked in the same contract - both verifiable on-chain and, as far as the data shows, never withdrawn across any graduated token. That&#8217;s a genuinely different risk profile from a launchpad with no enforced lock.</p></li><li><p><strong>Real Pons pool vs. copycat pool.</strong> Anyone can initialize a Uniswap v4 pool for any token. The only reliable way to identify the actual graduated Pons pool is the hook address on the pool - not the token address, not who called the graduation transaction (since graduation is permissionless, that can be a random keeper contract).</p></li></ul><h2>Why this matters more on Pons than on its competitors</h2><p>A separate Uniswap-built launchpad on Robinhood Chain, Pools.trade, out-launched Pons on its own first day, creating over ten thousand tokens against Pons&#8217; roughly seven thousand. Pools.trade puts tokens straight into a Uniswap v4 pool from block one with no bonding curve - which also means no snipe tax. That&#8217;s a completely different execution problem: on Pools.trade, raw speed genuinely is most of the edge. On Pons, it isn&#8217;t. A bot (or a &#8220;bot service&#8221;) that applies the same playbook to both is going to overpay by 99% on one of them.</p><p>That distinction - knowing which launchpad&#8217;s mechanics you&#8217;re actually trading, instead of running one generic strategy across &#8220;Robinhood Chain&#8221; as if it were a single market - is most of what separates a production trading system from a bundler script someone ported from Solana over a weekend.</p><h2>Where we come in</h2><p>This is the layer we build at <strong>Casatrick</strong> under our Pons Copy Trading infrastructure: protocol-aware execution logic for Robinhood Chain, not a generic mempool racer. If you&#8217;re evaluating a Pons-specific sniper or copy-trading build - for a desk, a fund, or your own capital - this is the level of detail we design at from day one: tax-curve-aware entries, dual-asset pricing for stock-quoted launches, and a risk layer that verifies liquidity locks rather than assuming them.</p><p><em>This is technical/educational content, not financial advice. Bonding-curve launches and memecoins carry high volatility and smart-contract risk regardless of execution quality  position size accordingly.</em></p><h2>FAQ</h2><p><strong>Does Pons have an official trading API?</strong> No - Pons&#8217; own documentation directs integrators to index the launch factory and each token&#8217;s bonding curve directly rather than calling a hosted API.</p><p><strong>What is the Pons &#8220;snipe tax&#8221;?</strong> A protocol-enforced, rapidly decaying tax on buys made in the first few seconds after a token launches - roughly 99% in the launch second, dropping to about 6% a second later and under 0.2% the second after that, based on the factory&#8217;s current settings.</p><p><strong>Is Pons launchpad liquidity actually locked?</strong> Yes, in two separate places for every graduated token: the seeded Uniswap v4 position and a further slice of token supply, both held in a dedicated locker contract.</p><p><strong>How is Pons different from Robinhood Chain&#8217;s other launchpad, Pools.trade?</strong> Pons runs every launch through a bonding curve with a snipe tax before graduating to Uniswap v4; Pools.trade skips the curve entirely and opens a v4 pool from block one with no equivalent tax, making it a pure speed game rather than a tax-timing game.</p><p><strong>Can a sniper bot get exempted from the snipe tax?</strong> Only if the token&#8217;s creator pre-declares that wallet as exempt at launch time - it&#8217;s an allowlist mechanic, not something achievable through faster execution alone.</p>]]></content:encoded></item><item><title><![CDATA[Building the Infrastructure Behind a Real-Time Token Scanner ]]></title><description><![CDATA[What happens between an onchain event and usable data? I'm building the pipeline that connects the two on Robinhood Chain.]]></description><link>https://casatrick.substack.com/p/building-the-infrastructure-behind-a-real-time-token-scanner</link><guid isPermaLink="false">https://casatrick.substack.com/p/building-the-infrastructure-behind-a-real-time-token-scanner</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Fri, 18 Sep 2026 06:22:34 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7623e4cd-df33-4e46-8596-57c724237c59_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One thing became obvious pretty quickly:</p><p><strong>Finding a token is not the hard part.</strong></p><p>The hard part is building a system that can watch what is happening onchain, understand it, turn it into clean data, and make that data available quickly enough for other systems to use.</p><p>That&#8217;s what I&#8217;m working on now.</p><p>A real-time token scanner.</p><p>Not just a page that lists token addresses.</p><p>The infrastructure underneath it.</p><h2>The idea</h2><p>The system starts with a very simple question:</p><blockquote><p>What is happening onchain right now?</p></blockquote><p>To answer that reliably, the pipeline needs to look something like this:</p><pre><code><code>Robinhood Chain
      &#8595;
Event Listener
      &#8595;
Event Decoder
      &#8595;
Token Normalizer
      &#8595;
Filtering
      &#8595;
Database / Cache
      &#8595;
API
      &#8595;
Alerts / Analytics</code></code></pre><p>Each part solves a different problem.</p><p>And most of the interesting work is not visible from the final interface.</p><h2>Watching the chain</h2><p>The first layer is the event listener.</p><p>I don&#8217;t want the application to constantly ask the chain:</p><blockquote><p>Did something happen?</p></blockquote><p>The system should instead stay connected and process relevant activity as it arrives.</p><p>Conceptually:</p><pre><code><code>Event arrives
     &#8595;
Detect
     &#8595;
Decode
     &#8595;
Validate
     &#8595;
Store</code></code></pre><p>Of course, production systems aren&#8217;t that clean.</p><p>Connections drop.</p><p>RPC requests fail.</p><p>Traffic spikes.</p><p>Events can be processed more than once.</p><p>So the listener needs to be designed around failure from the beginning.</p><h2>Turning raw events into useful information</h2><p>A blockchain event isn&#8217;t automatically application-ready data.</p><p>The next step is decoding it.</p><pre><code><code>Raw Event
    &#8595;
Identify
    &#8595;
Decode
    &#8595;
Validate
    &#8595;
Structured Data</code></code></pre><p>This is one of those areas where a small mistake can propagate through the entire system.</p><p>If the event is interpreted incorrectly, everything downstream is now operating on incorrect data.</p><p>So I&#8217;m treating validation as part of ingestion rather than something to bolt on later.</p><h2>The importance of normalization</h2><p>Once events have been decoded, I want the rest of the application to stop worrying about the underlying event format.</p><p>Instead, it works with a consistent internal representation.</p><p>Something roughly like:</p><pre><code><code>Token
&#9500;&#9472;&#9472; address
&#9500;&#9472;&#9472; chain
&#9500;&#9472;&#9472; creator
&#9500;&#9472;&#9472; timestamp
&#9500;&#9472;&#9472; liquidity
&#9500;&#9472;&#9472; volume
&#9492;&#9472;&#9472; metadata</code></code></pre><p>The schema will evolve.</p><p>That&#8217;s expected.</p><p>What&#8217;s important is having a stable interface between the chain-facing part of the system and everything built on top of it.</p><p>That separation becomes extremely useful later.</p><p>Search doesn&#8217;t need to understand RPC responses.</p><p>Analytics doesn&#8217;t need to understand event encoding.</p><p>An alerting service doesn&#8217;t need to know how the token was originally detected.</p><h2>Filtering the noise</h2><p>Onchain data is noisy.</p><p>A scanner can&#8217;t treat every event as equally useful.</p><p>There needs to be a filtering layer that can remove things such as:</p><ul><li><p>invalid contracts</p></li><li><p>incomplete records</p></li><li><p>malformed data</p></li><li><p>insufficient activity</p></li><li><p>irrelevant events</p></li><li><p>duplicates</p></li></ul><p>But I&#8217;m deliberately keeping this separate from trading logic.</p><p>That&#8217;s an important distinction.</p><p>The scanner should tell me:</p><p><strong>what happened.</strong></p><p>A strategy can later decide:</p><p><strong>what to do about it.</strong></p><p>That makes the underlying infrastructure useful beyond one particular strategy.</p><h2>Designing for failure</h2><p>One of the things I care about most with this kind of system is what happens when something goes wrong.</p><p>A scanner that works perfectly for an hour and then silently misses events isn&#8217;t really a real-time scanner.</p><p>So I&#8217;m thinking about:</p><ul><li><p>reconnects</p></li><li><p>retries</p></li><li><p>idempotent writes</p></li><li><p>checkpoints</p></li><li><p>structured logs</p></li><li><p>health checks</p></li><li><p>metrics</p></li></ul><p>before worrying too much about shaving tiny amounts of latency off individual functions.</p><p>My priority is roughly:</p><pre><code><code>Correctness
    &#8595;
Recoverability
    &#8595;
Observability
    &#8595;
Performance</code></code></pre><p>Once those fundamentals are solid, performance work becomes much easier to reason about.</p><h2>Where the latency actually comes from</h2><p>Eventually, real-time performance becomes important.</p><p>But the interesting thing is that the slowest part isn&#8217;t necessarily the code you expect.</p><p>The complete path might be:</p><pre><code><code>Onchain Event
      &#8595;
Listener
      &#8595;
Decoder
      &#8595;
Normalizer
      &#8595;
Database
      &#8595;
API / Alert</code></code></pre><p>Latency can come from anywhere:</p><ul><li><p>RPC response time</p></li><li><p>decoding</p></li><li><p>database writes</p></li><li><p>serialization</p></li><li><p>network requests</p></li><li><p>downstream processing</p></li></ul><p>So rather than guessing, I want to measure the complete path.</p><p>Real-time systems are usually an exercise in finding where the actual bottleneck is.</p><h2>Concurrency is another problem</h2><p>As activity increases, multiple things will happen simultaneously.</p><p>The system may be processing events while:</p><ul><li><p>performing lookups</p></li><li><p>writing records</p></li><li><p>updating caches</p></li><li><p>serving API requests</p></li></ul><p>That makes concurrency important.</p><p>But simply adding more workers isn&#8217;t necessarily the answer.</p><p>You can end up with:</p><pre><code><code>More events
    &#8595;
More workers
    &#8595;
More RPC requests
    &#8595;
More RPC pressure
    &#8595;
More failures</code></code></pre><p>So I&#8217;m more interested in <strong>controlled concurrency</strong> than maximum concurrency.</p><p>The system needs to absorb activity without turning an activity spike into its own failure.</p><h2>What comes after the scanner?</h2><p>This is the part I find most interesting.</p><p>Once the system can reliably transform onchain activity into structured data, the scanner becomes a foundation for other things.</p><pre><code><code>                 Token Data
                     &#9474;
        &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
        &#8595;            &#8595;            &#8595;
     Search       Analytics     Alerts
        &#9474;            &#9474;            &#9474;
        &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                     &#8595;
              Other Systems</code></code></pre><p>That could eventually support:</p><ul><li><p>token discovery</p></li><li><p>historical analytics</p></li><li><p>monitoring</p></li><li><p>real-time alerts</p></li><li><p>research</p></li><li><p>automated systems</p></li></ul><p>The scanner doesn&#8217;t need to know what every consumer wants to do with the data.</p><p>It just needs to produce good data.</p><h2>What&#8217;s next</h2><p>The current focus is the foundation.</p><p>From there, I want to explore:</p><ul><li><p>richer token metadata</p></li><li><p>historical activity</p></li><li><p>real-time alerts</p></li><li><p>token activity scoring</p></li><li><p>more efficient indexing</p></li><li><p>API access</p></li><li><p>additional onchain signals</p></li></ul><p>I&#8217;m deliberately building this layer by layer.</p><p>The interesting question isn&#8217;t:</p><blockquote><p>How do I find a new token?</p></blockquote><p>It&#8217;s:</p><blockquote><p><strong>How do I turn an onchain event into reliable information quickly enough that another system can use it?</strong></p></blockquote><p>That&#8217;s the engineering problem I&#8217;m interested in.</p><p>And the scanner is only the first piece.</p>]]></content:encoded></item><item><title><![CDATA[The RWA Infrastructure Robinhood Chain Will Need as Stock Tokens Grow]]></title><description><![CDATA[Robinhood Chain is becoming more interesting for a reason that goes beyond trading.]]></description><link>https://casatrick.substack.com/p/rwa-infrastructure-robinhood-chain-stock-tokens</link><guid isPermaLink="false">https://casatrick.substack.com/p/rwa-infrastructure-robinhood-chain-stock-tokens</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Thu, 17 Sep 2026 09:22:53 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20fc41b5-3091-44af-ac64-e6bbfd53c11e_1672x940.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The real opportunity is the infrastructure being built <strong>around Stock Tokens</strong>.</p><p>Robinhood describes Chain as an Ethereum-compatible Layer 2 designed for onchain financial infrastructure and real-world assets. Its Stock Tokens are standard ERC-20 assets with onchain Chainlink pricing, and Robinhood explicitly lists applications such as trading, lending, portfolio tracking, and other financial products.</p><p>Robinhood&#8217;s August 2026 monthly metrics also reported <strong>190+ Stock Tokens on Robinhood Chain</strong> and the launch of agentic crypto trading.</p><p>That changes the developer problem.</p><p>The question is no longer:</p><blockquote><p>&#8220;How do I interact with one token?&#8221;</p></blockquote><p>It&#8217;s:</p><blockquote><p><strong>&#8220;What infrastructure do I need to build a real financial application around hundreds of onchain assets?&#8221;</strong></p></blockquote><p>That&#8217;s where I think the larger RWA opportunity sits.</p><div><hr></div><h2>A Stock Token Is Only the Beginning</h2><p>From the user&#8217;s perspective, a Stock Token application might look simple:</p><pre><code><code>Choose Asset
     &#8595;
View Price
     &#8595;
View Portfolio
     &#8595;
Trade / Lend / Manage</code></code></pre><p>But behind that interface, the application needs to understand:</p><pre><code><code>Asset
Price
Contract
Portfolio
Transactions
Corporate Actions
Liquidity
Risk
Historical Data</code></code></pre><p>The more assets and users an application supports, the harder this becomes.</p><p>A financial application can&#8217;t simply read a token balance and call itself an RWA platform.</p><p>It needs a reliable data layer underneath it.</p><div><hr></div><h1>1. A Canonical Stock Token Registry</h1><p>The first piece of infrastructure I would build is an asset registry.</p><p>Robinhood maintains a live onchain asset registry and explicitly warns developers that a token with the same ticker or name at another address is not necessarily the canonical Robinhood Stock Token.</p><p>That means applications should identify assets using something more reliable than:</p><pre><code><code>"AAPL"</code></code></pre><p>The backend should know:</p><pre><code><code>Asset ID
Contract Address
Chain ID
Symbol
Decimals
Underlying Asset
Current Multiplier
Trading Capabilities
Status</code></code></pre><p>For example:</p><pre><code><code>{
  "symbol": "AAPL",
  "chainId": 4663,
  "contractAddress": "0x...",
  "decimals": 18,
  "status": "active"
}</code></code></pre><p>This sounds basic.</p><p>It becomes important when your platform supports hundreds of assets.</p><div><hr></div><h1>2. Price Normalization Is a Real Problem</h1><p>One of the less obvious parts of Stock Token infrastructure is pricing.</p><p>Robinhood provides read-only APIs for Stock Token asset metadata and prices. The API documentation explains that the REST <code>/prices</code> endpoint returns the raw underlying-equity bid/ask, while the onchain Chainlink feed returns a multiplier-adjusted value. Applications combining the two need to account for <code>currentMultiplier</code>.</p><p>So I would create a dedicated pricing service.</p><pre><code><code>Robinhood API
      +
Chainlink
      +
Onchain Data
      &#8595;
Price Normalizer
      &#8595;
Canonical Price
      &#8595;
Applications</code></code></pre><p>Every application can then use the same normalized price:</p><pre><code><code>Trading
Lending
Portfolio
Analytics
Risk
Liquidation</code></code></pre><p>Without this layer, different parts of the application can end up calculating different values for the same asset.</p><p>That is exactly the type of infrastructure problem a client eventually discovers after the first version is already live.</p><div><hr></div><h1>3. Corporate Actions Need to Be Part of the Data Model</h1><p>RWA systems can&#8217;t treat an asset as a static ERC-20 forever.</p><p>Robinhood&#8217;s Stock Token APIs expose corporate-action data, including forward splits, reverse splits, cash dividends, and stock dividends. Robinhood also uses an onchain multiplier to adjust the shares-per-token relationship while maintaining the raw token balance.</p><p>That means an analytics platform needs to understand:</p><pre><code><code>Raw Balance
      &#8595;
Multiplier
      &#8595;
Effective Exposure
      &#8595;
Portfolio Value</code></code></pre><p>A historical analytics system also needs to know <strong>when</strong> a corporate action occurred.</p><p>Otherwise:</p><blockquote><p>today&#8217;s balance &#215; today&#8217;s price</p></blockquote><p>isn&#8217;t enough to accurately explain historical portfolio performance.</p><p>This is the kind of detail that separates a basic token dashboard from actual RWA infrastructure.</p><div><hr></div><h1>4. The Portfolio Engine</h1><p>Once the asset and price layers exist, the next step is portfolio state.</p><p>A portfolio service should calculate:</p><pre><code><code>Token Balance
Position Value
Portfolio Weight
Realized PnL
Unrealized PnL
Exposure
Historical Allocation</code></code></pre><p>Conceptually:</p><pre><code><code>Wallet
  &#8595;
Token Balances
  &#8595;
Asset Registry
  &#8595;
Price Service
  &#8595;
Position Engine
  &#8595;
Portfolio State</code></code></pre><p>The client-facing product could then expose:</p><pre><code><code>Portfolio Value       $482,310
Stock Tokens               18
Largest Position          21%
Daily PnL                +1.4%
Total Exposure           87%</code></code></pre><p>Now the same backend can power a wallet interface, analytics dashboard, AI portfolio manager, or lending product.</p><div><hr></div><h1>5. Onchain Analytics</h1><p>The next layer is understanding what is actually happening onchain.</p><p>An RWA analytics system could track:</p><pre><code><code>Transfers
Swaps
Holders
Liquidity
Wallet Activity
Transaction History
Token Flows</code></code></pre><p>Then calculate:</p><pre><code><code>24h Volume
Unique Holders
Net Inflows
Net Outflows
Liquidity Changes
Top Wallets
Historical Activity</code></code></pre><p>That creates a much more useful product than a page that simply displays the token price.</p><p>For an RWA startup, this could become:</p><blockquote><p><strong>The data platform behind the application.</strong></p></blockquote><div><hr></div><h1>6. Real-Time Data</h1><p>A traditional analytics platform can update every few minutes.</p><p>A trading or risk application can&#8217;t always afford that delay.</p><p>Robinhood Chain provides RPC and WebSocket connectivity, while the documentation also exposes a sequencer feed for low-latency updates.</p><p>That allows an architecture like:</p><pre><code><code>Robinhood Chain
      &#8595;
WebSocket / Sequencer
      &#8595;
Event Processor
      &#8595;
State Store
      &#8595;
    API
      &#8595;
Dashboard / AI / Risk</code></code></pre><p>Instead of every application building its own event-processing system, a shared data service can expose normalized events.</p><p>For example:</p><pre><code><code>{
  "type": "swap",
  "pool": "0x...",
  "tokenIn": "TOKEN_A",
  "tokenOut": "USDG",
  "amount": "2500",
  "block": 12345678
}</code></code></pre><p>Now other products can consume the data without understanding raw logs.</p><div><hr></div><h1>7. RWA Risk Infrastructure</h1><p>Once Stock Tokens start being used in financial applications, basic analytics isn&#8217;t enough.</p><p>You need risk infrastructure.</p><p>For example:</p><pre><code><code>Asset Price
    &#8595;
Collateral Value
    &#8595;
Exposure
    &#8595;
Risk Rules
    &#8595;
Alert / Action</code></code></pre><p>Possible products include:</p><ul><li><p>portfolio exposure monitoring</p></li><li><p>collateral monitoring</p></li><li><p>concentration limits</p></li><li><p>liquidity alerts</p></li><li><p>oracle health checks</p></li><li><p>price-deviation detection</p></li><li><p>liquidation monitoring</p></li></ul><p>This can sit underneath an RWA lending protocol or operate as a standalone risk API.</p><div><hr></div><h1>8. APIs Become the Product</h1><p>Once you have all of this data, you can expose it through an API.</p><p>For example:</p><pre><code><code>GET /assets
GET /assets/:symbol
GET /prices/:symbol
GET /holders/:token
GET /wallets/:address
GET /wallets/:address/positions
GET /wallets/:address/transactions
GET /portfolio/:address
GET /corporate-actions
GET /liquidity/:token</code></code></pre><p>Now a founder doesn&#8217;t have to build the entire data pipeline from scratch.</p><p>They can build their application on top of your infrastructure.</p><p>That is a very different business from building one dashboard for one team.</p><div><hr></div><h1>9. The Same Data Layer Can Power AI</h1><p>This is where RWA infrastructure and AI begin to overlap.</p><p>An AI portfolio manager needs:</p><pre><code><code>Market Data
Portfolio State
Historical Data
Corporate Actions
Risk Data</code></code></pre><p>All of that should come from the infrastructure layer.</p><p>Then:</p><pre><code><code>RWA Data Platform
        &#8595;
AI Agent Tools
        &#8595;
Portfolio Analysis
        &#8595;
Recommendation</code></code></pre><p>The AI doesn&#8217;t need direct access to raw blockchain data.</p><p>It can call:</p><pre><code><code>getPortfolio()
getPosition()
getPrice()
getHistoricalPerformance()
getRisk()</code></code></pre><p>That makes the agent layer much cleaner.</p><div><hr></div><h1>10. AI Agents Will Need Financial Infrastructure Too</h1><p>Robinhood is already moving toward agentic finance. Its July 2026 announcement described Agentic Trading for crypto, where AI models can access Robinhood data and tools while users define capital allocations and safety guardrails.</p><p>But an agentic application still needs infrastructure underneath it.</p><p>A useful architecture is:</p><pre><code><code>                 AI Agent
                    &#8595;
                Tool Layer
                    &#8595;
              RWA Data API
                    &#8595;
            Portfolio / Risk
                    &#8595;
             Policy Engine
                    &#8595;
              Transaction
                    &#8595;
             Robinhood Chain</code></code></pre><p>This is where developers can build something more valuable than another AI chatbot.</p><div><hr></div><h1>11. Data Infrastructure Will Become More Important as the Asset Set Grows</h1><p>The current direction matters.</p><p>Robinhood&#8217;s August 2026 metrics reported more than 190 Stock Tokens on Robinhood Chain.</p><p>As the asset set expands, applications have to deal with:</p><pre><code><code>More Assets
     &#8595;
More Contracts
     &#8595;
More Prices
     &#8595;
More Events
     &#8595;
More Portfolio States
     &#8595;
More Analytics</code></code></pre><p>At that point, manually querying contracts from a frontend doesn&#8217;t scale as a product architecture.</p><p>Teams need:</p><p><strong>indexers</strong></p><p><strong>data pipelines</strong></p><p><strong>normalized APIs</strong></p><p><strong>caching</strong></p><p><strong>historical databases</strong></p><p><strong>real-time streams</strong></p><p><strong>monitoring</strong></p><p>That&#8217;s the infrastructure layer I would focus on.</p><div><hr></div><h1>12. What I&#8217;d Build</h1><p>If I were building an RWA infrastructure product for Robinhood Chain today, I&#8217;d start with a unified data platform:</p><pre><code><code>                 Robinhood Chain
                       &#9474;
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#8595;                 &#8595;
        Onchain Events       Stock Token API
              &#9474;                 &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                       &#8595;
                Data Normalizer
                       &#8595;
              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#8595;        &#8595;        &#8595;
           Assets    Prices   Events
              &#9474;        &#9474;        &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                       &#8595;
                 Portfolio Engine
                       &#8595;
              Analytics / Risk API
                       &#8595;
        &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
        &#8595;              &#8595;              &#8595;
    Dashboard         AI           Lending</code></code></pre><p>Then other products can consume the same foundation.</p><p>That&#8217;s the interesting part.</p><p>You don&#8217;t have to build one application.</p><p>You build infrastructure that lets <strong>other applications exist</strong>.</p><div><hr></div><h1>13. The Client Opportunity</h1><p>Think about the questions a founder will ask as their RWA product grows:</p><blockquote><p>&#8220;Where do I get reliable Stock Token data?&#8221;</p><p>&#8220;How do I index wallet positions?&#8221;</p><p>&#8220;How do I handle corporate actions?&#8221;</p><p>&#8220;How do I normalize prices?&#8221;</p><p>&#8220;How do I calculate portfolio exposure?&#8221;</p><p>&#8220;How do I stream onchain events?&#8221;</p><p>&#8220;How do I give my AI agent access to this data?&#8221;</p><p>&#8220;How do I monitor risk?&#8221;</p></blockquote><p>Those are all engineering problems.</p><p>And they can become separate products or components of a larger RWA platform.</p><div><hr></div><h1>14. The Bigger Picture</h1><p>The obvious Robinhood Chain opportunity is trading.</p><p>The less obvious opportunity is everything underneath it.</p><pre><code><code>              Stock Tokens
                    &#9474;
       &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
       &#8595;            &#8595;            &#8595;
     Data         Trading      Lending
       &#8595;            &#8595;            &#8595;
   Analytics     Execution      Risk
       &#8595;            &#8595;            &#8595;
        &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472; AI &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                    &#8595;
             Financial Apps</code></code></pre><p>Robinhood Chain is explicitly positioning itself as infrastructure for onchain financial products and RWAs, and its current developer stack already includes RPC/WebSockets, Stock Token APIs, Chainlink feeds, account-abstraction infrastructure, and other components needed to build financial applications.</p><p>That means the developer opportunity isn&#8217;t limited to:</p><blockquote><p>&#8220;Build a trading bot.&#8221;</p></blockquote><p>It can be:</p><blockquote><p><strong>Build the data, analytics, risk, AI, and application infrastructure that financial products need.</strong></p></blockquote><p>That&#8217;s the direction I&#8217;d watch as Robinhood Chain grows.</p><h2>What I Would Build for a Client</h2><p>If a team came to me with an RWA product on Robinhood Chain, I&#8217;d first look at the infrastructure underneath the frontend:</p><pre><code><code>Asset Registry
Data Ingestion
Price Normalization
Portfolio Engine
Real-Time Events
Analytics API
Risk Layer
AI Tools
Execution
Monitoring</code></code></pre><p>The frontend may be what users see.</p><p>But the infrastructure underneath it is what makes the product work.</p>]]></content:encoded></item><item><title><![CDATA[Polymarket Trading Bot Development: Build a Custom Trading Bot ]]></title><description><![CDATA[From strategy logic to real-time data, risk, execution, backtesting, monitoring, and PnL - building custom Polymarket trading systems around your strategy.]]></description><link>https://casatrick.substack.com/p/polymarket-trading-bot-development</link><guid isPermaLink="false">https://casatrick.substack.com/p/polymarket-trading-bot-development</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Wed, 16 Sep 2026 06:48:25 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c0c5b59-466b-45b7-99ae-f6189fe7d452_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A lot of people interested in automated Polymarket trading already have some version of a strategy.</p><p><strong>Github</strong>: <strong><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpolymarket-trading-bot">polymarket trading bot</a><br></strong><br>It might be:</p><ul><li><p>a Python script</p></li><li><p>a Rust script</p></li><li><p>a Typescript</p></li><li><p>a research notebook</p></li><li><p>a spreadsheet with trading rules</p></li><li><p>a backtest</p></li><li><p>a signal model</p></li><li><p>a set of entry and exit conditions</p></li><li><p>an arbitrage idea</p></li><li><p>a market-making strategy</p></li><li><p>or simply an idea that has never been automated</p></li></ul><p>The difficult part is often not coming up with the strategy.</p><p>The difficult part is turning that strategy into a reliable system that can operate against a live prediction market.</p><p>That means dealing with real-time market data, order books, execution, partial fills, latency, position state, risk limits, failures, monitoring, and reconciliation.</p><p>That&#8217;s the part I build.</p><div><hr></div><h2>What a Polymarket trading bot actually needs</h2><p>A production trading bot is much more than:</p><pre><code><code>if signal:
    buy()</code></code></pre><p>A real system looks more like:</p><pre><code><code>               Strategy
                   &#8595;
             Signal Engine
                   &#8595;
          Market State / Data
                   &#8595;
             Risk Engine
                   &#8595;
          Execution Engine
                   &#8595;
                Orders
                   &#8595;
           Fills / Positions
                   &#8595;
             Reconciliation
                   &#8595;
            Monitoring / PnL</code></code></pre><p>Every layer matters.</p><p>A strategy can be profitable on paper and still fail when it meets a real order book.</p><p>That&#8217;s why I treat the bot as a <strong>trading system</strong>, not just a script.</p><div><hr></div><h1>1. Start with your strategy</h1><p>The first step isn&#8217;t writing code.</p><p>It&#8217;s understanding exactly what the strategy is supposed to do.</p><p>For example:</p><pre><code><code>Market qualifies
        &#8595;
Signal appears
        &#8595;
Entry condition satisfied
        &#8595;
   Risk check
        &#8595;
   Place order
        &#8595;
Monitor execution
        &#8595;
 Position updated
        &#8595;
 Exit condition</code></code></pre><p>The strategy may already exist.</p><p>My job is to turn those rules into deterministic software.</p><p>That can include:</p><ul><li><p>entry conditions</p></li><li><p>exit conditions</p></li><li><p>signal calculations</p></li><li><p>market filters</p></li><li><p>position sizing</p></li><li><p>timing rules</p></li><li><p>maximum exposure</p></li><li><p>market selection</p></li><li><p>stop conditions</p></li><li><p>portfolio constraints</p></li></ul><p>The strategy remains yours.</p><p>The engineering makes it executable.</p><div><hr></div><h1>2. Real-time Polymarket market data</h1><p>A trading system needs current information.</p><p>That means building a reliable market-data layer rather than repeatedly making ad-hoc API requests from strategy code.</p><p>Depending on the system, that can include:</p><ul><li><p>market metadata</p></li><li><p>order-book data</p></li><li><p>bid/ask prices</p></li><li><p>trades</p></li><li><p>market status</p></li><li><p>WebSocket streams</p></li><li><p>price changes</p></li><li><p>liquidity</p></li><li><p>volume</p></li><li><p>position state</p></li></ul><p>The architecture I use separates market data from strategy logic.</p><p>For example:</p><pre><code><code>Polymarket
    &#8595;
WebSocket / API
    &#8595;
Market Data Layer
    &#8595;
Normalized State
    &#8595;
Strategy Engine</code></code></pre><p>This separation becomes important once the system gets more complicated.</p><p>The strategy shouldn&#8217;t need to know how a WebSocket reconnects.</p><p>The execution engine shouldn&#8217;t need to calculate the strategy&#8217;s signal.</p><p>Each component should have a clear responsibility.</p><div><hr></div><h1>3. The order book changes everything</h1><p>One of the biggest differences between a backtest and live trading is execution.</p><p>A strategy may say:</p><blockquote><p>Buy at 42&#162;.</p></blockquote><p>But that doesn&#8217;t necessarily mean you can buy your desired size at 42&#162;.</p><p>There may not be enough liquidity.</p><p>The available prices can change while your order is being submitted.</p><p>Your order can partially fill.</p><p>The market can move.</p><p>An order can remain open longer than expected.</p><p>This is why I pay particular attention to the execution layer.</p><p>A useful execution system needs to understand:</p><ul><li><p>available liquidity</p></li><li><p>bid/ask spread</p></li><li><p>order size</p></li><li><p>partial fills</p></li><li><p>order status</p></li><li><p>cancellation</p></li><li><p>retries</p></li><li><p>stale orders</p></li><li><p>execution latency</p></li><li><p>position reconciliation</p></li></ul><p>The difference between a strategy that works in a spreadsheet and one that works with real money is often here.</p><div><hr></div><h1>4. Risk management is part of the strategy</h1><p>A trading strategy tells you when you want to trade.</p><p>A risk engine determines whether you&#8217;re <strong>allowed</strong> to trade.</p><p>For example:</p><pre><code><code>Signal
  &#8595;
Is market eligible?
  &#8595;
Is exposure below limit?
  &#8595;
Is portfolio risk acceptable?
  &#8595;
Is available capital sufficient?
  &#8595;
Is the position size valid?
  &#8595;
Execute</code></code></pre><p>Depending on the strategy, risk controls can include:</p><ul><li><p>maximum position size</p></li><li><p>maximum market exposure</p></li><li><p>portfolio exposure</p></li><li><p>bankroll allocation</p></li><li><p>daily loss limits</p></li><li><p>drawdown protection</p></li><li><p>inventory limits</p></li><li><p>market eligibility filters</p></li><li><p>emergency shutdown</p></li><li><p>execution limits</p></li></ul><p>These controls shouldn&#8217;t be scattered throughout the codebase.</p><p>They should be explicit parts of the system.</p><div><hr></div><h1>5. Backtest before deploying capital</h1><p>One of the most useful things a trading bot can do before trading live is <strong>fail in simulation</strong>.</p><p>That&#8217;s a good thing.</p><p>A simple backtest can easily produce unrealistic results if it assumes:</p><pre><code><code>signal &#8594; instant fill &#8594; requested price</code></code></pre><p>Real execution isn&#8217;t that clean.</p><p>A more realistic simulation needs to consider things such as:</p><ul><li><p>order-book depth</p></li><li><p>liquidity</p></li><li><p>spread</p></li><li><p>slippage</p></li><li><p>partial fills</p></li><li><p>execution timing</p></li><li><p>position limits</p></li><li><p>fees</p></li><li><p>market resolution</p></li><li><p>capital constraints</p></li></ul><p>I&#8217;ve spent a significant amount of time testing Polymarket strategies against real order-book data for exactly this reason.</p><p>A strategy that looks excellent under midpoint assumptions can look very different once execution constraints are introduced.</p><div><hr></div><h1>6. Execution latency matters</h1><p>Latency isn&#8217;t always the most important variable.</p><p>But when a strategy depends on short-lived opportunities, it can become critical.</p><p>A simplified execution path might be:</p><pre><code><code>Market event
    &#8595;
Receive data
    &#8595;
Update state
    &#8595;
Calculate signal
    &#8595;
Risk check
    &#8595;
Create order
    &#8595;
Submit order
    &#8595;
Exchange receives order
    &#8595;
  Fill</code></code></pre><p>Every step takes time.</p><p>I&#8217;ve previously rebuilt parts of my own Polymarket trading infrastructure in Rust after seeing execution delays become a practical problem.</p><p>The lesson wasn&#8217;t simply:</p><blockquote><p>Rust is faster.</p></blockquote><p>The more important lesson was:</p><blockquote><p><strong>Measure the entire execution path.</strong></p></blockquote><p>You need to know where the latency actually comes from before optimizing it.</p><div><hr></div><h1>7. Position state needs to be trustworthy</h1><p>A trading bot shouldn&#8217;t assume that its internal state is always correct.</p><p>Consider this:</p><pre><code><code>Bot thinks:
Position = 500

Actual exchange state:
Position = 430</code></code></pre><p>If the bot continues trading based on the first number, risk calculations can become wrong.</p><p>That&#8217;s why production systems need reconciliation.</p><p>A simplified model is:</p><pre><code><code>Internal State
      &#8595;
  Compare
      &#8595;
Exchange State
      &#8595;
Detect Difference
      &#8595;
  Reconcile
      &#8595;
  Continue</code></code></pre><p>This becomes especially important after:</p><ul><li><p>network failures</p></li><li><p>process restarts</p></li><li><p>partial fills</p></li><li><p>rejected orders</p></li><li><p>API errors</p></li><li><p>WebSocket disconnects</p></li><li><p>unexpected execution</p></li></ul><p>A bot that can trade but cannot reliably recover is not a finished trading system.</p><div><hr></div><h1>8. Monitoring and PnL</h1><p>Once a bot is live, you need to know what it&#8217;s doing.</p><p>At minimum, I want visibility into things like:</p><pre><code><code>Markets monitored
Signals generated
Orders submitted
Orders filled
Open positions
Realized PnL
Unrealized PnL
Exposure
Errors
Latency
Connection status</code></code></pre><p>A dashboard isn&#8217;t just decoration.</p><p>It&#8217;s part of operating the system.</p><p>If a strategy suddenly stops trading, I want to know whether:</p><ul><li><p>there are no signals</p></li><li><p>the market-data connection failed</p></li><li><p>orders are being rejected</p></li><li><p>the risk engine is blocking trades</p></li><li><p>the bot lost synchronization</p></li><li><p>the process crashed</p></li></ul><p>Without observability, debugging a live trading system becomes guesswork.</p><div><hr></div><h1>9. Different strategies need different systems</h1><p>There isn&#8217;t one universal Polymarket bot.</p><p>The architecture depends heavily on the strategy.</p><p>For example, a <strong>momentum system</strong> might care about:</p><ul><li><p>short-term price movement</p></li><li><p>market state</p></li><li><p>volume</p></li><li><p>timing</p></li><li><p>execution speed</p></li></ul><p>An <strong>arbitrage system</strong> may care more about:</p><ul><li><p>relationships between markets</p></li><li><p>pricing discrepancies</p></li><li><p>execution synchronization</p></li><li><p>liquidity</p></li><li><p>transaction costs</p></li></ul><p>A <strong>market-making system</strong> has a different set of requirements:</p><ul><li><p>quoting</p></li><li><p>inventory</p></li><li><p>spread management</p></li><li><p>adverse selection</p></li><li><p>order replacement</p></li><li><p>exposure</p></li></ul><p>A <strong>wallet-following system</strong> needs yet another architecture:</p><pre><code><code>Wallet Activity
      &#8595;
Event Detection
      &#8595;
Wallet Filtering
      &#8595;
Signal Generation
      &#8595;
    Risk
      &#8595;
  Execution</code></code></pre><p>That&#8217;s why I don&#8217;t believe in selling one generic &#8220;Polymarket bot.&#8221;</p><p>The system should be designed around the strategy.</p><div><hr></div><h1>10. What if you already have a strategy?</h1><p>This is probably the most important part.</p><p>You don&#8217;t need to arrive with a finished bot.</p><p>You might have:</p><p><strong>A strategy document</strong></p><pre><code><code>If probability &lt; X
and volume &gt; Y
and condition Z is true:
    enter</code></code></pre><p>Or:</p><p><strong>A Python prototype</strong></p><pre><code><code>signal = calculate_signal(data)

if signal &gt; threshold:
    trade()</code></code></pre><p>Or:</p><p><strong>A backtest</strong></p><p>You already know the strategy works under certain assumptions, but you don&#8217;t have the infrastructure to run it live.</p><p>Or even:</p><p><strong>An idea</strong></p><p>You know what you want to trade and approximately how you want it to work, but haven&#8217;t implemented anything yet.</p><p>The engineering process can turn that into:</p><pre><code><code>Your Strategy
      &#8595;
Formal Specification
      &#8595;
Market Data
      &#8595;
Signal Engine
      &#8595;
Risk Engine
      &#8595;
Execution
      &#8595;
Backtesting
      &#8595;
Paper Trading
      &#8595;
Production
      &#8595;
Monitoring</code></code></pre><div><hr></div><h1>You bring the strategy. I build the system.</h1><p>This is the kind of Polymarket work I&#8217;m interested in.</p><p>Not just:</p><blockquote><p>&#8220;Build me a bot.&#8221;</p></blockquote><p>But:</p><blockquote><p>&#8220;I have a strategy. Can you turn it into a reliable automated trading system?&#8221;</p></blockquote><p>That&#8217;s a much more interesting engineering problem.</p><p>The implementation can include whatever the strategy actually requires:</p><ul><li><p>Polymarket API/CLOB integration</p></li><li><p>real-time WebSocket market data</p></li><li><p>order-book processing</p></li><li><p>strategy implementation</p></li><li><p>signal generation</p></li><li><p>risk management</p></li><li><p>position sizing</p></li><li><p>automated execution</p></li><li><p>backtesting</p></li><li><p>paper trading</p></li><li><p>monitoring</p></li><li><p>PnL tracking</p></li><li><p>position reconciliation</p></li><li><p>failure recovery</p></li><li><p>production deployment</p></li></ul><p>The exact architecture depends on the strategy.</p><div><hr></div><h1>My own Polymarket engineering work</h1><p>I&#8217;ve built and tested different parts of this stack myself rather than treating automated trading as a theoretical exercise.</p><p>That includes work around:</p><ul><li><p>real-time market data</p></li><li><p>WebSocket infrastructure</p></li><li><p>order-book processing</p></li><li><p>execution systems</p></li><li><p>latency measurement</p></li><li><p>risk controls</p></li><li><p>backtesting</p></li><li><p>strategy research</p></li><li><p>automated trading infrastructure</p></li><li><p>monitoring and PnL</p></li></ul><p>I&#8217;ve also written about the individual engineering problems because each one can become a failure point in a live system.</p><p>You can explore the technical work separately:</p><p><strong>Execution</strong></p><p>&#8594; How execution latency and order handling affect real trading</p><p><strong>Market data</strong></p><p>&#8594; Building real-time Polymarket WebSocket infrastructure</p><p><strong>Backtesting</strong></p><p>&#8594; Replaying real order-book data instead of assuming perfect fills</p><p><strong>Risk</strong></p><p>&#8594; Volatility filters, sizing and exposure controls</p><p><strong>Strategy research</strong></p><p>&#8594; Short-duration prediction-market strategies and their limitations</p><p><strong>Analytics</strong></p><p>&#8594; Studying large numbers of Polymarket trading bots and wallet behavior</p><p>The point isn&#8217;t that one component makes a profitable strategy.</p><p>It&#8217;s that a serious trading system needs all of them to work together.</p><div><hr></div><h1>From research to production</h1><p>My preferred workflow is:</p><pre><code><code>1. Understand the strategy
          &#8595;
2. Formalize the rules
          &#8595;
3. Design the architecture
          &#8595;
4. Connect market data
          &#8595;
5. Implement the strategy
          &#8595;
6. Add risk controls
          &#8595;
7. Build execution
          &#8595;
8. Backtest
          &#8595;
9. Paper trade
          &#8595;
10. Deploy
          &#8595;
11. Monitor
          &#8595;
12. Iterate</code></code></pre><p>The objective isn&#8217;t to rush from an idea to live capital.</p><p>It&#8217;s to remove as many unknowns as possible before doing that.</p><div><hr></div><h1>What I can build</h1><p>Depending on the strategy, a custom Polymarket system can include:</p><h3>Strategy automation</h3><p>Turn an existing trading strategy or research model into executable code.</p><h3>Trading bots</h3><p>Automated systems that monitor markets, generate signals, manage positions and execute trades.</p><h3>Arbitrage systems</h3><p>Automated detection and execution of defined pricing relationships across markets.</p><h3>Market-making systems</h3><p>Automated quoting, inventory management and risk controls.</p><h3>Real-time trading infrastructure</h3><p>WebSocket data processing, market state, event handling and low-latency execution.</p><h3>Backtesting infrastructure</h3><p>Historical market/order-book replay with realistic execution assumptions.</p><h3>Risk systems</h3><p>Position limits, sizing, exposure controls, drawdown protection and emergency shutdowns.</p><h3>Monitoring</h3><p>Live dashboards, PnL, positions, execution statistics, alerts and system health.</p><div><hr></div><h1>The important part</h1><p>I don&#8217;t think the valuable part of a trading bot is the word <strong>&#8220;bot.&#8221;</strong></p><p>The valuable part is the system underneath it.</p><p>A strategy needs data.</p><p>Data needs reliable state.</p><p>Signals need risk controls.</p><p>Orders need execution logic.</p><p>Positions need reconciliation.</p><p>Live systems need monitoring.</p><p>And everything needs to survive the conditions that weren&#8217;t present in the original backtest.</p><p>That&#8217;s what turns a trading idea into trading infrastructure.</p><div><hr></div><h2>Have a Polymarket strategy you want automated?</h2><p>If you already have a strategy, prototype, backtest, research model, or simply a set of trading rules, I can help turn it into a production-oriented Polymarket trading system.</p><p><strong>You bring the strategy. I build the system around it.</strong></p><p>That can mean starting from an existing Python/Rust prototype, or building the infrastructure from scratch.</p><p>If you&#8217;re looking for a custom Polymarket trading bot rather than another generic bot template, <strong>get in touch.<br></strong></p>]]></content:encoded></item><item><title><![CDATA[How to Build a Pons Token Scanner on Robinhood Chain]]></title><description><![CDATA[From Pons launch events to normalized onchain data, filtering, ranking, and the infrastructure behind Robinhood Chain trading applications.]]></description><link>https://casatrick.substack.com/p/pons-token-scanner-robinhood-chain</link><guid isPermaLink="false">https://casatrick.substack.com/p/pons-token-scanner-robinhood-chain</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Mon, 14 Sep 2026 06:18:08 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74124843-8f3a-46e3-92fc-fbfef584b7d2_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A token scanner sounds simple.</p><p>Watch for new launches, collect the data, apply a few filters, and show the results.</p><p>In practice, a useful scanner needs much more than a list of recently deployed tokens.</p><p>It needs reliable onchain data, deterministic processing, enough context to evaluate an opportunity, and an architecture that can eventually feed other trading applications.</p><p>That is the direction I&#8217;m taking with the Pons tooling I&#8217;m building on <strong>Robinhood Chain</strong>.</p><p>The goal is not to create another throwaway scanner script.</p><p>The goal is to build a reusable data and application layer that can eventually support scanners, copy trading, snipers, analytics, and other trading automation.</p><div><hr></div><h2>The scanner is only the top of the stack</h2><p>The simplest architecture looks like:</p><pre><code><code>New Token
   &#8595;
Filter
   &#8595;
Display</code></code></pre><p>That hides most of the engineering.</p><p>A more realistic system looks like:</p><pre><code><code>Robinhood Chain
      &#8595;
Pons Contracts + Events
      &#8595;
Pons SDK
      &#8595;
Onchain Data / Indexing
      &#8595;
Normalized Launch State
      &#8595;
Scanner Filters
      &#8595;
Ranking
      &#8595;
Scanner Output</code></code></pre><p>The scanner is the application layer.</p><p>Everything underneath it determines whether the output is trustworthy.</p><div><hr></div><h1>Starting with Pons launch events</h1><p>The first useful primitive is the ability to detect and decode Pons launches reliably.</p><p>The Pons SDK I&#8217;ve been building provides the foundation for this:</p><ul><li><p>Robinhood Chain connection</p></li><li><p>Pons V1/V2 contract integration</p></li><li><p>factory reads</p></li><li><p><code>TokenLaunched</code> event decoding</p></li><li><p>chunked event queries</p></li><li><p>typed launch data</p></li><li><p>unit tests</p></li><li><p>live RPC integration tests</p></li></ul><p>The current test baseline is:</p><p><strong>30/30 unit tests passing</strong></p><p><strong>3/3 live integration tests passing</strong></p><p>The live integration path also verifies a real Pons <code>TokenLaunched</code> event on Robinhood Chain.</p><p>That gives the scanner a real source of truth.</p><p>Rather than scraping a website or depending on a third-party API, the scanner can begin from protocol-level events.</p><div><hr></div><h1>Why event-driven scanning matters</h1><p>Suppose the scanner wants to identify newly launched tokens.</p><p>One approach is continuous polling:</p><pre><code><code>Every few seconds:
    Query everything
    Compare with previous results
    Repeat</code></code></pre><p>That becomes inefficient quickly.</p><p>An event-driven architecture is more natural:</p><pre><code><code>TokenLaunched
      &#8595;
Decode
      &#8595;
Normalize
      &#8595;
Persist
      &#8595;
Evaluate</code></code></pre><p>The event itself becomes the trigger for downstream processing.</p><p>This creates a cleaner path toward real-time applications later.</p><p>The same architecture can eventually support:</p><ul><li><p>launch monitoring</p></li><li><p>token scanners</p></li><li><p>alerts</p></li><li><p>sniper systems</p></li><li><p>analytics</p></li><li><p>automated trading</p></li></ul><div><hr></div><h1>What the scanner actually needs to know</h1><p>A scanner shouldn&#8217;t just answer:</p><blockquote><p>&#8220;What launched?&#8221;</p></blockquote><p>It should eventually answer:</p><blockquote><p>&#8220;What launched, what do we know about it, and does it deserve attention?&#8221;</p></blockquote><p>That requires normalized launch data.</p><p>A useful record can include information such as:</p><pre><code><code>Token
Deployer
Factory
Pool
Pair token
Block number
Transaction hash
Launch configuration
Initial buy information
Launch timestamp / block context</code></code></pre><p>The exact schema can evolve.</p><p>The important part is that downstream applications should not need to understand raw event logs every time they want to use launch information.</p><p>That responsibility belongs in the data layer.</p><div><hr></div><h1>Normalization is where the SDK becomes useful</h1><p>Raw blockchain events are designed for contracts.</p><p>Application code needs something different.</p><p>Instead of passing raw logs through the entire system, the SDK can normalize them into a stable representation.</p><p>Conceptually:</p><pre><code><code>Raw EVM Log
    &#8595;
Pons Event Decoder
    &#8595;
Typed Launch Event
    &#8595;
Normalized Launch</code></code></pre><p>That gives the scanner a cleaner interface.</p><p>It also means changes in low-level event handling do not necessarily require changes to the application layer.</p><p>This is one reason I prefer building the SDK first rather than jumping straight into the scanner.</p><div><hr></div><h1>Filtering</h1><p>Once launch data is normalized, the scanner can apply rules.</p><p>The first version should stay simple.</p><p>For example:</p><pre><code><code>Launch discovered
      &#8595;
Valid token?
      &#8595;
Valid pool?
      &#8595;
Required metadata available?
      &#8595;
Within scanner criteria?
      &#8595;
Keep / Reject</code></code></pre><p>A good filtering layer should be:</p><p><strong>Deterministic</strong></p><p>The same input should produce the same result.</p><p><strong>Explainable</strong></p><p>A rejected token should have a reason.</p><p><strong>Composable</strong></p><p>New criteria should not require rewriting the scanner.</p><p>A result might therefore look like:</p><pre><code><code>status: ACCEPTED
reason: PASSED_FILTERS</code></code></pre><p>or:</p><pre><code><code>status: REJECTED
reason: MISSING_POOL_DATA
</code>That becomes much more useful when the scanner grows into a trading system.</code></pre><div><hr></div><h1>Ranking is different from filtering</h1><p>Filtering answers:</p><blockquote><p>Should this token remain in the candidate set?</p></blockquote><p>Ranking answers:</p><blockquote><p>Which candidates deserve attention first?</p></blockquote><p>Those should stay separate.</p><p>For example:</p><pre><code><code>Launches
   &#8595;
Eligibility Filter
   &#8595;
Candidate Set
   &#8595;
Ranking
   &#8595;
Top Opportunities</code></code></pre><p>A ranking system could eventually incorporate different signals such as:</p><ul><li><p>recency</p></li><li><p>launch activity</p></li><li><p>liquidity</p></li><li><p>wallet activity</p></li><li><p>transaction behavior</p></li><li><p>pool characteristics</p></li></ul><p>For the MVP, I would avoid pretending that a complicated &#8220;alpha score&#8221; is already necessary.</p><p>The initial goal is clean infrastructure.</p><div><hr></div><h1>Why a scanner should not become a trading bot too early</h1><p>It is tempting to go directly from:</p><blockquote><p>New token detected</p></blockquote><p>to:</p><blockquote><p>Buy token.</p></blockquote><p>That is where many experimental trading systems become difficult to reason about.</p><p>The scanner should first establish a reliable candidate pipeline:</p><pre><code><code>Discovery
   &#8595;
Normalization
   &#8595;
Filtering
   &#8595;
Ranking
   &#8595;
Opportunity</code></code></pre><p>Then another layer can decide whether an opportunity should become a trading signal.</p><p>That separation leaves room for:</p><pre><code><code>Scanner
   &#8595;
Research
   &#8595;
Signal
   &#8595;
Risk
   &#8595;
Execution</code></code></pre><p>The scanner does not need to know how a transaction gets executed.</p><div><hr></div><h1>The same data can power multiple applications</h1><p>This is the bigger reason for building the scanner on top of shared infrastructure.</p><p>Once launch and market state are available, multiple applications can consume them.</p><pre><code><code>                  &#9484;&#9472;&#9472; Scanner
                  &#9474;
                  &#9500;&#9472;&#9472; Copy Trading
Pons Data &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472; Sniper
                  &#9474;
                  &#9500;&#9472;&#9472; Analytics
                  &#9474;
                  &#9492;&#9472;&#9472; Automation</code></code></pre><p>The scanner is therefore not an isolated product.</p><p>It becomes one consumer of the underlying Robinhood Chain data layer.</p><div><hr></div><h1>Scanner &#8594; sniper</h1><p>A scanner can eventually become the first step in a sniper architecture.</p><p>Conceptually:</p><pre><code><code>TokenLaunched
      &#8595;
Detection
      &#8595;
Eligibility
      &#8595;
Fast state checks
      &#8595;
    Risk
      &#8595;
Execution</code></code></pre><p>The important distinction is that a scanner can prioritize <strong>visibility and correctness</strong>, while a sniper introduces much stronger latency and execution requirements.</p><p>Those concerns should not be mixed prematurely.</p><p>The same underlying event infrastructure can support both.</p><div><hr></div><h1>Scanner &#8594; copy trading</h1><p>The same platform can also connect launch information with wallet intelligence.</p><p>For example:</p><pre><code><code>New Launch
    &#8595;
Wallet Activity
    &#8595;
Relevant Wallets
    &#8595;
Behavior Analysis
    &#8595;
Copy-Trading Signal</code></code></pre><p>Again, the value comes from sharing infrastructure.</p><p>You don&#8217;t want a separate blockchain ingestion stack for every application.</p><div><hr></div><h1>Building the MVP</h1><p>The first useful Pons scanner does not need a dashboard.</p><p>It needs a reliable pipeline.</p><p>The initial implementation is centered around:</p><pre><code><code>Pons Events
    &#8595;
Launch Normalization
    &#8595;
Filtering
    &#8595;
Ranking
    &#8595;
Queryable Output</code></code></pre><p>The output can start as a CLI, structured JSON, or another simple developer-facing interface.</p><p>The important thing is that another application can consume it.</p><p>That makes the scanner infrastructure, not just a UI.</p><div><hr></div><h1>What I am deliberately not doing yet</h1><p>There are several things I do not want to hide behind the word &#8220;scanner.&#8221;</p><p>This stage does not require:</p><ul><li><p>live transaction execution</p></li><li><p>private-key management</p></li><li><p>an elaborate trading strategy</p></li><li><p>a giant scoring model</p></li><li><p>a complex distributed system</p></li><li><p>a production cloud architecture</p></li></ul><p>Those can come later.</p><p>The current focus is:</p><p><strong>Reliable data &#8594; deterministic candidate generation &#8594; reusable output</strong></p><p>That foundation is more valuable than prematurely adding complexity.</p><div><hr></div><h1>Where this fits in the broader Robinhood Chain stack</h1><p>The project is gradually taking shape as:</p><pre><code><code>Pons SDK
    &#8595;
Onchain Indexing
    &#8595;
Persistent State
    &#8595;
Wallet Intelligence
    &#8595;
Scanner
    &#8595;
Copy Trading
    &#8595;
Sniper / Bundler
    &#8595;
Risk + Execution</code></code></pre><p>Each layer has a clear responsibility.</p><p>The scanner sits in the middle: close enough to the data layer to react quickly, but abstract enough to feed multiple applications.</p><p>That makes it an important bridge between infrastructure and client-facing products.</p><div><hr></div><h1>Why this matters for custom trading systems</h1><p>A client asking for a &#8220;trading bot&#8221; often isn&#8217;t really asking for a single script.</p><p>They may actually need:</p><ul><li><p>launch monitoring</p></li><li><p>wallet tracking</p></li><li><p>market-state indexing</p></li><li><p>filtering</p></li><li><p>alerting</p></li><li><p>copy trading</p></li><li><p>execution</p></li><li><p>risk controls</p></li><li><p>dashboards</p></li><li><p>analytics</p></li></ul><p>Those systems share infrastructure.</p><p>That is the reason I&#8217;m building the stack from the bottom up.</p><p>Instead of producing one bot and starting over for the next project, the goal is to create reusable components that can be assembled into different Robinhood Chain trading applications.</p><div><hr></div><h1>What comes next</h1><p>The scanner is one step in a larger sequence:</p><pre><code><code>SDK
 &#8595;
Indexer
 &#8595;
State
 &#8595;
Wallet Intelligence
 &#8595;
Scanner
 &#8595;
Copy Trading
 &#8595;
Sniper / Bundler
 &#8595;
Execution</code></code></pre><p>The next challenge is making the scanner increasingly useful without turning it into a monolith.</p><p>That means improving data quality, real-time processing, filtering, ranking, observability, and integration points.</p><p>The eventual goal is a reusable Robinhood Chain trading infrastructure stack.</p><div><hr></div><h1>Building a Pons scanner or Robinhood Chain trading system?</h1><p>I&#8217;m building custom infrastructure and automation around Robinhood Chain, including:</p><p><strong>Pons SDKs &#183; onchain indexers &#183; wallet intelligence &#183; token scanners &#183; copy-trading systems &#183; snipers &#183; bundlers &#183; execution infrastructure</strong></p><p>The focus is on building reusable systems underneath the application, not just isolated scripts.</p><p><strong>GitHub:</strong> <a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Frobinhood-trading-tools">[Robinhood Chain Trading Tools repository]</a></p><p>If you&#8217;re building a Robinhood Chain trading product and need the underlying infrastructure, this is the area I&#8217;m currently working in.</p><div><hr></div><h2>Final thought</h2><p>The scanner itself is only the visible part.</p><p>The valuable part underneath it is:</p><p><strong>events &#8594; normalized state &#8594; filtering &#8594; ranking &#8594; reusable signals</strong></p><p>Once that layer is reliable, it becomes possible to build much more than a scanner.</p><p>It becomes infrastructure for an entire family of Robinhood Chain trading applications.</p>]]></content:encoded></item><item><title><![CDATA[Building Robinhood Chain Trading Infrastructure: From Pons SDK to Copy Trading]]></title><description><![CDATA[Pons SDK &#8594; Indexer &#8594; Wallet Intelligence &#8594; Copy Trading. Building the infrastructure underneath Robinhood Chain trading applications.]]></description><link>https://casatrick.substack.com/p/robinhood-chain-trading-infrastructure</link><guid isPermaLink="false">https://casatrick.substack.com/p/robinhood-chain-trading-infrastructure</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Thu, 10 Sep 2026 14:10:38 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58d8997f-e986-4ef5-a710-1235b62cc580_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A lot of trading projects start with a bot.</p><p>A sniper.</p><p>A copy-trading bot.</p><p>A bundler.</p><p>A scanner.</p><p>The application gets all the attention.</p><p>But before any of those products can work reliably, there is another problem to solve:</p><p><strong>the infrastructure underneath them.</strong></p><p>That is what I&#8217;m building on Robinhood Chain.</p><p>I started with Pons because it gives me a concrete onchain environment to work against. The first step was a TypeScript SDK for Pons on Robinhood Chain.</p><p>That SDK now connects to the real network, supports the Pons V1/V2 factory layer, reads deployed contracts, decodes real <code>TokenLaunched</code> events, and has been tested against both unit fixtures and the live RPC.</p><p>The next step is turning that foundation into something much more useful:</p><p><strong>indexed state &#8594; wallet intelligence &#8594; trading applications.</strong></p><p>The long-term goal is not one bot.</p><p>It is a reusable infrastructure layer that can support multiple Robinhood Chain trading products.</p><div><hr></div><h2>The stack I&#8217;m building</h2><p>The overall architecture looks like:</p><pre><code><code>                  ROBINHOOD CHAIN
                        &#8595;
                  PONS / ADAPTERS
                        &#8595;
                   EVENT LAYER
                        &#8595;
                       SDK
                        &#8595;
                    INDEXER
                        &#8595;
                  MARKET STATE
                        &#8595;
             &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
             &#8595;          &#8595;          &#8595;
         Wallet Data  Token Data  Pool Data
             &#8595;          &#8595;          &#8595;
             &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                        &#8595;
                  INTELLIGENCE
                        &#8595;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#8595;             &#8595;             &#8595;
       Scanner      Copy Trading   Analytics
          &#8595;             &#8595;             &#8595;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                        &#8595;
                       Risk
                        &#8595;
                    Execution
                        &#8595;
                 Reconciliation</code></code></pre><p>The important idea is that the application is the top of the stack.</p><p>The data layer underneath it should be reusable.</p><div><hr></div><h2>Why I started with Pons</h2><p>I could have started by building a generic Robinhood Chain trading bot.</p><p>That would have been faster to demonstrate.</p><p>It would also have made the architecture harder to reason about.</p><p>Instead, I wanted to understand the protocol first.</p><p>That means:</p><p><strong>contracts</strong></p><p>&#8594; <strong>events</strong></p><p>&#8594; <strong>state</strong></p><p>&#8594; <strong>applications</strong></p><p>Pons gives me a real protocol to work against while I build that foundation.</p><p>This also creates a cleaner path to supporting other Robinhood Chain ecosystems later.</p><p>Pons can be the first adapter.</p><p>It doesn&#8217;t have to be the final boundary.</p><div><hr></div><h2>The first milestone: Pons SDK</h2><p>The first milestone is already working.</p><p>The SDK provides:</p><ul><li><p>Robinhood Chain connection</p></li><li><p>Pons V1/V2 factory support</p></li><li><p>contract reads</p></li><li><p><code>TokenLaunched</code> decoding</p></li><li><p>chunked historical event queries</p></li><li><p>launch queries</p></li><li><p>real onchain fixtures</p></li></ul><p>The verification is equally important.</p><h3>Unit tests</h3><pre><code><code>&#10003; tests/events.test.ts    &#8212; 8
&#10003; tests/client.test.ts    &#8212; 9
&#10003; tests/launches.test.ts  &#8212; 13

30/30 tests passing</code></code></pre><h3>Live integration</h3><pre><code><code>&#10003; public Robinhood Chain RPC connection
&#10003; latest block read
&#10003; official PONS reference-token contract read
&#10003; live factory verification

3/3 integration tests passing</code></code></pre><p>I care about both.</p><p>A unit test proves the code behaves correctly in isolation.</p><p>A live integration test checks whether the assumptions still match the deployed network.</p><div><hr></div><h2>Real onchain data, not just mocks</h2><p>The event decoder is also tested against a real Pons <code>TokenLaunched</code> event.</p><p>One verified V1 launch resolves to:</p><pre><code><code>Version:          v1
Token:            0x39dBED3a2bd333467115dE45665cC57F813C4571
Factory:          0x0c37a24F5D23A486FA692d1500881d698B1F77a4
Pool:             0x10CC6BD38112cAc182db90B6a71d8Bb5939526bA
Block:            8963150
Position ID:      109216
Transaction:      0x1f54f25fec2d963dcb338ecb8b46a6eb123198a5c7a746d34cb2dbe78d074af8
Log Index:        45</code></code></pre><p>The reason I include evidence like this is simple:</p><p>There is a big difference between:</p><blockquote><p>&#8220;I wrote a Pons SDK.&#8221;</p></blockquote><p>and:</p><blockquote><p>&#8220;The SDK connects to mainnet, reads deployed contracts, decodes real events, and passes live integration tests.&#8221;</p></blockquote><p>The second is much more useful.</p><div><hr></div><h1>From SDK to indexed state</h1><p>An SDK solves one problem:</p><blockquote><p><strong>How do I interact with the protocol?</strong></p></blockquote><p>An indexer solves another:</p><blockquote><p><strong>How do I maintain a usable historical representation of what happened?</strong></p></blockquote><p>The architecture changes from:</p><pre><code><code>Blockchain
    &#8595;
   SDK
    &#8595;
Application</code></code></pre><p>to:</p><pre><code><code>Blockchain
    &#8595;
Events
    &#8595;
  SDK
    &#8595;
Indexer
    &#8595;
Database
    &#8595;
Queryable State</code></code></pre><p>This is where the project starts becoming infrastructure.</p><p>The first indexer target is deliberately narrow:</p><p><code>TokenLaunched</code></p><p>The job is to turn those events into persistent launch records.</p><div><hr></div><h2>Why idempotency matters</h2><p>An indexer should be safe to run more than once.</p><p>Suppose I process a range containing 100 launches.</p><p>Then I accidentally process the same range again.</p><p>A bad indexer produces:</p><pre><code><code>100 launches
+
100 duplicate launches
=
200 records</code></code></pre><p>A reliable indexer should produce:</p><pre><code><code>100 launches
+
same range again
=
100 records</code></code></pre><p>That means the system needs deterministic event identity.</p><p>For an onchain event, a natural identity is:</p><pre><code><code>transaction hash + log index</code></code></pre><p>The database can enforce that uniqueness.</p><p>This isn&#8217;t an exciting feature for a screenshot.</p><p>It becomes very important when the system runs continuously.</p><div><hr></div><h1>The next layer: wallet intelligence</h1><p>Once historical state exists, we can stop thinking only in terms of launches.</p><p>We can start asking:</p><p><strong>Which wallets are active?</strong></p><p><strong>What are they doing?</strong></p><p><strong>When did they enter?</strong></p><p><strong>What tokens are they interacting with?</strong></p><p><strong>Is this a one-off transaction or a recurring behavior?</strong></p><p>The architecture becomes:</p><pre><code><code>Onchain Events
      &#8595;
Indexed Activity
      &#8595;
Wallet State</code></code></pre><p>That creates the foundation for a completely different category of application.</p><div><hr></div><h1>Copy trading is one application</h1><p>Copy trading sounds simple from the outside:</p><pre><code><code>Wallet A buys
     &#8595;
Wallet B copies</code></code></pre><p>A real system is more like:</p><pre><code><code>Wallet Activity
      &#8595;
Wallet State
      &#8595;
Trade Detection
      &#8595;
Filtering
      &#8595;
    Risk
      &#8595;
Copy-Trade Signal
      &#8595;
Execution
      &#8595;
Reconciliation</code></code></pre><p>That is the architecture I&#8217;m interested in.</p><p>The important part isn&#8217;t blindly replicating a transaction.</p><p>It is deciding:</p><blockquote><p><strong>Which activity is actually worth following?</strong></p></blockquote><div><hr></div><h2>Not every wallet should be copied</h2><p>A wallet can make transactions that are irrelevant to a copy-trading strategy.</p><p>For example:</p><ul><li><p>tiny trades</p></li><li><p>test activity</p></li><li><p>excluded tokens</p></li><li><p>unsupported markets</p></li><li><p>stale signals</p></li><li><p>excessive exposure</p></li><li><p>activity outside the watchlist</p></li></ul><p>So the system needs a policy layer.</p><p>Conceptually:</p><pre><code><code>Trade Candidate
      &#8595;
   Filter
      &#8595;
    Risk
      &#8595;
   Signal</code></code></pre><p>Each decision should be explainable.</p><p>For example:</p><pre><code><code>Wallet:
0x...

Trade:
BUY

Filter:
&#10003; watched wallet
&#10003; allowed token
&#10003; valid size

Risk:
&#10003; exposure within limit

Result:
APPROVED</code></code></pre><p>Or:</p><pre><code><code>Result:
REJECTED

Reason:
Token excluded by policy</code></code></pre><p>This is far more useful than a black-box &#8220;copy bot.&#8221;</p><div><hr></div><h1>Risk should not live inside the strategy</h1><p>One architectural mistake I try to avoid is giving the strategy too much authority.</p><p>The strategy might identify an interesting trade.</p><p>That doesn&#8217;t mean the system should automatically execute it.</p><p>I prefer:</p><pre><code><code>Strategy
   &#8595;
Risk
   &#8595;
Execution</code></code></pre><p>The strategy asks:</p><blockquote><p>Is this interesting?</p></blockquote><p>The risk layer asks:</p><blockquote><p>Can I safely take it?</p></blockquote><p>The execution layer asks:</p><blockquote><p>How should I attempt it?</p></blockquote><p>Three different responsibilities.</p><div><hr></div><h1>Execution comes later</h1><p>For the current research system, execution remains deliberately separate.</p><p>The copy-trade pipeline can stop at:</p><pre><code><code>Copy-Trade Signal</code></code></pre><p>before any real transaction exists.</p><p>That gives us room for:</p><p><strong>research mode</strong></p><p>&#8594; <strong>paper execution</strong></p><p>&#8594; <strong>controlled execution</strong></p><p>&#8594; <strong>live execution</strong></p><p>without rewriting the data and decision layers.</p><p>This separation also makes testing much easier.</p><div><hr></div><h1>The same infrastructure can support a scanner</h1><p>A scanner is another application of the same foundation.</p><p>Instead of asking:</p><blockquote><p>&#8220;Should I copy this wallet?&#8221;</p></blockquote><p>it asks:</p><blockquote><p>&#8220;What is happening right now?&#8221;</p></blockquote><p>The underlying data can remain the same.</p><pre><code><code>Pons Events
     &#8595;
Indexer
     &#8595;
Market State
     &#8595;
Scanner</code></code></pre><p>Possible signals eventually include:</p><p><strong>new launches</strong></p><p><strong>rapid activity</strong></p><p><strong>volume changes</strong></p><p><strong>liquidity changes</strong></p><p><strong>wallet activity</strong></p><p><strong>pool activity</strong></p><p>Again, the scanner doesn&#8217;t need its own blockchain integration from scratch.</p><div><hr></div><h1>And a bundler</h1><p>The same thing happens with a bundler.</p><p>From the outside, a bundler looks like a transaction tool.</p><p>Underneath it needs:</p><p><strong>state</strong></p><p><strong>transaction coordination</strong></p><p><strong>ordering</strong></p><p><strong>failure handling</strong></p><p><strong>execution</strong></p><p><strong>monitoring</strong></p><p>That means it can sit on the same base:</p><pre><code><code>Shared Infrastructure
       &#8595;
    Bundler</code></code></pre><p>The data and execution layers can be reused.</p><div><hr></div><h1>And a sniper</h1><p>A sniper has an even stronger timing dependency.</p><p>A basic description might be:</p><blockquote><p>Detect launch &#8594; buy.</p></blockquote><p>The engineering problem is closer to:</p><pre><code><code>Event
 &#8595;
Detection
 &#8595;
Validation
 &#8595;
State
 &#8595;
Risk
 &#8595;
Execution
 &#8595;
Confirmation
 &#8595;
Reconciliation</code></code></pre><p>The difference between a toy script and a trading system is everything in the middle.</p><p>That is exactly where I want the infrastructure to be strong.</p><div><hr></div><h1>Why this matters for clients</h1><p>A client doesn&#8217;t necessarily want:</p><blockquote><p>&#8220;A TypeScript SDK.&#8221;</p></blockquote><p>They may want:</p><p><strong>a copy-trading system</strong></p><p><strong>a token scanner</strong></p><p><strong>a wallet tracker</strong></p><p><strong>a bundler</strong></p><p><strong>a sniper</strong></p><p><strong>a trading backend</strong></p><p><strong>a real-time onchain data system</strong></p><p>Those look like different products.</p><p>But underneath them are recurring engineering problems:</p><p><strong>data ingestion</strong></p><p><strong>state management</strong></p><p><strong>event processing</strong></p><p><strong>risk</strong></p><p><strong>execution</strong></p><p><strong>reconciliation</strong></p><p><strong>observability</strong></p><p>That&#8217;s why I&#8217;m building the infrastructure as a reusable system instead of creating disconnected one-off bots.</p><div><hr></div><h1>The broader repository</h1><p>This is also why the project is expanding beyond a single SDK package.</p><p>The broader direction is:</p><pre><code><code>Robinhood Chain Trading Tools

&#9500;&#9472;&#9472; Pons SDK
&#9500;&#9472;&#9472; Historical Indexer
&#9500;&#9472;&#9472; Wallet Intelligence
&#9500;&#9472;&#9472; Copy Trading
&#9500;&#9472;&#9472; Scanner
&#9500;&#9472;&#9472; Bundler
&#9492;&#9472;&#9472; Sniper</code></code></pre><p>Pons is the first ecosystem adapter.</p><p>The goal is to eventually make the underlying architecture reusable across Robinhood Chain applications.</p><div><hr></div><h1>What I&#8217;m building next</h1><p>The current progression is:</p><pre><code><code>[x] Robinhood Chain connection
[x] Pons V1/V2 integration
[x] Contract reads
[x] TokenLaunched decoding
[x] Historical launch queries
[x] 30/30 unit tests
[x] 3/3 live integration tests

&#8594; Historical indexer
&#8594; Persistent state
&#8594; Wallet intelligence
&#8594; Real-time events
&#8594; Copy-trade research
&#8594; Scanner
&#8594; Bundler
&#8594; Sniper</code></code></pre><p>I&#8217;m intentionally not trying to build all of those at once.</p><p>The infrastructure should mature in layers.</p><div><hr></div><h1>What I&#8217;m not trying to optimize for</h1><p>I don&#8217;t want to optimize for:</p><blockquote><p>&#8220;How quickly can I publish another bot?&#8221;</p></blockquote><p>I want to optimize for:</p><blockquote><p><strong>&#8220;How much reusable infrastructure can I build that makes the next product faster and more reliable?&#8221;</strong></p></blockquote><p>That&#8217;s a different approach.</p><p>Instead of:</p><pre><code><code>Bot A
Bot B
Bot C
Bot D</code></code></pre><p>I want:</p><pre><code><code>Shared Infrastructure
        &#8595;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#8595;       &#8595;        &#8595;
Bot A  Bot B    Bot C</code></code></pre><p>One foundation.</p><p>Multiple applications.</p><div><hr></div><h1>The bigger direction</h1><p>I&#8217;ve spent a lot of time building trading systems around prediction markets.</p><p>Robinhood Chain gives me a different environment to explore the same broader problem:</p><p><strong>How do you turn real-time market and onchain data into reliable autonomous systems?</strong></p><p>That&#8217;s where the project is heading.</p><p>Not just:</p><p><strong>Pons</strong></p><p>Not just:</p><p><strong>copy trading</strong></p><p>Not just:</p><p><strong>sniping</strong></p><p>But:</p><blockquote><p><strong>autonomous trading systems and onchain market infrastructure.</strong></p></blockquote><div><hr></div><h1>Final thought</h1><p>The easiest thing to build is often the last thing people see.</p><p>The bot.</p><p>The dashboard.</p><p>The scanner.</p><p>The interface.</p><p>Underneath it is a much harder system:</p><p><strong>events &#8594; state &#8594; intelligence &#8594; risk &#8594; execution &#8594; reconciliation</strong></p><p>That&#8217;s the part I&#8217;m building first.</p><p>The Pons SDK was the foundation.</p><p>The indexer turns it into state.</p><p>The application layer turns that state into something useful.</p><p>And eventually, the same infrastructure can support copy trading, scanners, bundlers, sniping systems, and other Robinhood Chain automation.</p><p><strong>Build the infrastructure once. Reuse it across the applications.<br><br><a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Frobinhood-trading-tools">https://github.com/casatrickdev/robinhood-trading-tools</a></strong></p>]]></content:encoded></item><item><title><![CDATA[Building a Pons SDK on Robinhood Chain: Contracts, Events & Onchain Data]]></title><description><![CDATA[30/30 unit tests. 3/3 live integration tests. Here's how I built the first Pons SDK layer from contracts and onchain events to typed data.]]></description><link>https://casatrick.substack.com/p/pons-sdk-robinhood-chain</link><guid isPermaLink="false">https://casatrick.substack.com/p/pons-sdk-robinhood-chain</guid><dc:creator><![CDATA[Casatrick]]></dc:creator><pubDate>Mon, 07 Sep 2026 12:16:56 GMT</pubDate><enclosure url="iframe.php?url=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ac8cb66-5813-4fa0-b4ad-da704dcce8df_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>30/30 unit tests pass.</strong></p><p><strong>3/3 live integration tests pass.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="iframe.php?url=https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%212YKL%21%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2YKL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 424w, https://substackcdn.com/image/fetch/$s_!2YKL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 848w, https://substackcdn.com/image/fetch/$s_!2YKL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 1272w, https://substackcdn.com/image/fetch/$s_!2YKL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 1456w" sizes="100vw"><img src="iframe.php?url=https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%212YKL%21%2Cw_1456%2Cc_limit%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png" width="775" height="472" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:472,&quot;width&quot;:775,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17857,&quot;alt&quot;:&quot;pons-sdk test result&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://casatrick.substack.com/i/214531819?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="pons-sdk test result" title="pons-sdk test result" srcset="https://substackcdn.com/image/fetch/$s_!2YKL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 424w, https://substackcdn.com/image/fetch/$s_!2YKL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 848w, https://substackcdn.com/image/fetch/$s_!2YKL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 1272w, https://substackcdn.com/image/fetch/$s_!2YKL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214a4e8a-ecb6-49d9-a53c-b46e74a93193_775x472.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">pons-sdk test result</figcaption></figure></div><p>The SDK connects to Robinhood Chain, reads the official Pons V1 and V2 factories, decodes real <code>TokenLaunched</code> events, and exposes the results as structured TypeScript data. The source code is <a href="iframe.php?url=https%3A%2F%2Fgithub.com%2Fcasatrickdev%2Fpons-sdk">available on GitHub</a></p><p>I started here deliberately.</p><p>Before building a scanner, analytics platform, or trading system, I wanted a reliable infrastructure layer for turning Pons&#8217;s onchain activity into data that other applications can actually use.</p><p>The first milestone is:</p><pre><code><code>Robinhood Chain
       &#8595;
Pons Contracts
       &#8595;
Onchain Events
       &#8595;
  Typed SDK</code></code></pre><p>The next milestone is:</p><pre><code><code>Events
   &#8595;
Indexer
   &#8595;
Persistent State</code></code></pre><p>This article is about the first part.</p><div><hr></div><h2>Why start with an SDK?</h2><p>When a new trading ecosystem appears, the obvious thing to build is usually a bot.</p><p>A scanner.</p><p>A sniper.</p><p>An analytics dashboard.</p><p>Something that trades.</p><p>I&#8217;m taking the opposite approach.</p><p>I want to start underneath the application layer.</p><p>The first question is:</p><blockquote><p><strong>Can I reliably turn the protocol&#8217;s raw onchain data into structured state?</strong></p></blockquote><p>If that foundation is unreliable, everything built on top of it becomes harder to trust.</p><p>So the architecture starts with:</p><pre><code><code>Pons Contracts
      &#8595;
   Events
      &#8595;
     SDK
      &#8595;
   Indexer
      &#8595;
 Analytics
      &#8595;
  Scanner
      &#8595;
Trading Systems</code></code></pre><p>The SDK is the first reusable layer.</p><p>Once it works, everything above it becomes an application problem.</p><div><hr></div><h2>Connecting to Robinhood Chain</h2><p>The first step was connecting the SDK to Robinhood Chain.</p><p>The SDK uses:</p><pre><code><code>Chain ID: 4663
RPC: https://rpc.mainnet.chain.robinhood.com</code></code></pre><p>I kept the RPC configuration behind the client rather than scattering it through the codebase.</p><p>The public API is intentionally simple:</p><pre><code><code>const pons = new PonsClient();

const blockNumber = await pons.getBlockNumber();</code></code></pre><p>The important thing here isn&#8217;t the number of lines of code.</p><p>It&#8217;s the fact that the client can connect to the actual network and read live blockchain state.</p><p>The integration test successfully connected to the public Robinhood Chain RPC and read the latest block.</p><p>That established the first foundation:</p><p><strong>the chain layer works against mainnet.</strong></p><div><hr></div><h2>Supporting the Pons contract surface</h2><p>The next layer is Pons itself.</p><p>Rather than embedding contract addresses throughout the codebase, I separated them into a dedicated contracts module:</p><pre><code><code>src/
  contracts/
    addresses.ts
    abis.ts</code></code></pre><p>The SDK supports both:</p><ul><li><p>Pons V1</p></li><li><p>Pons V2</p></li></ul><p>That matters because the current Pons ecosystem isn&#8217;t represented by a single static contract.</p><p>The client needs to know which factory version it is talking to, while keeping the public SDK API simple.</p><p>Conceptually:</p><pre><code><code>type PonsVersion = "v1" | "v2";</code></code></pre><p>and:</p><pre><code><code>const PONS_CONTRACTS = {
  v1: {
    factory: "...",
  },
  v2: {
    factory: "...",
  },
};</code></code></pre><p>The actual addresses and ABIs are taken from the deployed/official contract sources rather than invented or hard-coded inside application logic.</p><p>That makes the SDK easier to maintain as the protocol evolves.</p><div><hr></div><h2>Verifying the factory onchain</h2><p>Once the chain and contract configuration were in place, I wanted to verify that the deployed Pons contracts behaved as expected.</p><p>The live integration test successfully called:</p><pre><code><code>getLaunchedToken()</code></code></pre><p>against the V1 legacy factory using the official PONS reference token.</p><p>The result included:</p><pre><code><code>{
  "exists": true
}</code></code></pre><p>I also verified the V2 factory path through a live <code>canLaunch</code> call.</p><p>This is important because there is a big difference between:</p><blockquote><p>&#8220;The ABI compiles.&#8221;</p></blockquote><p>and:</p><blockquote><p>&#8220;The SDK successfully communicates with the deployed contracts on the real network.&#8221;</p></blockquote><p>I care about the second one.</p><div><hr></div><h2>Decoding <code>TokenLaunched</code></h2><p>After contract reads were working, the next step was event decoding.</p><p>Raw blockchain logs are useful, but they aren&#8217;t a pleasant application-level interface.</p><p>I wanted the SDK to turn a Pons factory event into a clean typed object.</p><p>The relevant code lives under:</p><pre><code><code>src/
  events/
    getTokenLaunchedLogs.ts
    decodeTokenLaunched.ts</code></code></pre><p>The flow is:</p><pre><code><code>RPC
 &#8595;
getLogs
 &#8595;
Pons Factory
 &#8595;
TokenLaunched
 &#8595;
Decoder
 &#8595;
Typed PonsLaunch</code></code></pre><p>That gives application code a much cleaner interface than working directly with raw log topics and encoded data.</p><div><hr></div><h2>This isn&#8217;t a synthetic test</h2><p>One thing I wanted to avoid was proving the SDK only with fabricated blockchain data.</p><p>So the event decoder is tested against real onchain logs.</p><p>One verified Pons V1 launch resolves to:</p><pre><code><code>{
  "version": "v1",
  "factory": "0x0c37a24F5D23A486FA692d1500881d698B1F77a4",
  "token": "0x39dBED3a2bd333467115dE45665cC57F813C4571",
  "deployer": "0xB9F5f4Ea1AF1F5d3678470eb98e8FBdcadEb24b0",
  "dexFactory": "0x1f7d7550B1b028f7571E69A784071F0205FD2EfA",
  "pairToken": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
  "pool": "0x10CC6BD38112cAc182db90B6a71d8Bb5939526bA",
  "dexId": "0",
  "launchConfigId": "0",
  "positionId": "109216",
  "restrictionsEndBlock": "25526532",
  "initialBuyAmount": "100000000000000000",
  "blockNumber": "8963150",
  "transactionHash": "0x1f54f25fec2d963dcb338ecb8b46a6eb123198a5c7a746d34cb2dbe78d074af8",
  "transactionIndex": "8",
  "logIndex": "45"
}</code></code></pre><p>The useful part isn&#8217;t the raw addresses by themselves.</p><p>It&#8217;s that a raw protocol event can now become a stable, strongly typed object inside an application.</p><p>That is the beginning of an indexable data model.</p><div><hr></div><h2>Why event identity matters</h2><p>An event isn&#8217;t just:</p><blockquote><p>&#8220;Something happened.&#8221;</p></blockquote><p>It also needs a deterministic identity.</p><p>For indexed blockchain data, a useful event identity is:</p><pre><code><code>transactionHash + logIndex</code></code></pre><p>That becomes important later when the indexer reprocesses a block range.</p><p>Suppose the indexer crashes.</p><p>Suppose the process restarts.</p><p>Suppose the same block range gets processed twice.</p><p>You don&#8217;t want the database to contain duplicate launch records.</p><p>The event identity gives the persistence layer a way to make indexing idempotent.</p><p>This is one of those details that isn&#8217;t very exciting from the outside, but becomes important as soon as the system has to run continuously.</p><div><hr></div><h2>Block-range chunking</h2><p>Another problem appears when querying historical data.</p><p>A naive implementation might request a very large range:</p><pre><code><code>getLogs({
  fromBlock: 1n,
  toBlock: "latest",
});</code></code></pre><p>That may work in a tiny test.</p><p>It isn&#8217;t a good assumption for a reusable SDK or historical indexer.</p><p>So the SDK supports chunked event queries.</p><p>Conceptually:</p><pre><code><code>Requested Block Range
        &#8595;
Split Into Chunks
        &#8595;
    getLogs()
        &#8595;
     Decode
        &#8595;
      Merge
        &#8595;
  Deduplicate
        &#8595;
      Sort</code></code></pre><p>That means callers don&#8217;t need to understand RPC-specific range limitations just to retrieve historical launches.</p><p>It also gives us a cleaner foundation for the next stage: indexing.</p><div><hr></div><h2>Keeping the public API simple</h2><p>Internally, the SDK has to deal with:</p><ul><li><p>chain configuration</p></li><li><p>contract versions</p></li><li><p>RPC requests</p></li><li><p>event topics</p></li><li><p>block ranges</p></li><li><p>decoding</p></li><li><p>normalization</p></li></ul><p>None of that should leak unnecessarily into every application.</p><p>The public API should look more like:</p><pre><code><code>const pons = new PonsClient();

const launches = await pons.getLaunches({
  fromBlock: 8991118n,
  toBlock: "latest",
});</code></code></pre><p>The SDK handles the details.</p><p>The application gets structured data.</p><p>That is the abstraction I want.</p><div><hr></div><h2>The test suite</h2><p>I care about tests that prove both software behavior and network compatibility.</p><p>The unit test suite currently has:</p><pre><code><code>&#10003; tests/events.test.ts   - 8 tests
&#10003; tests/client.test.ts   - 9 tests
&#10003; tests/launches.test.ts - 13 tests

Test Files: 3 passed
Tests:      30 passed</code></code></pre><p>So:</p><p><strong>30/30 unit tests pass.</strong></p><p>Those tests cover the core client, launch logic, event decoding, and related behavior.</p><p>But unit tests alone aren&#8217;t enough for blockchain infrastructure.</p><div><hr></div><h2>Live integration tests</h2><p>I also have a separate integration suite that runs against the public Robinhood Chain RPC.</p><p>Current result:</p><pre><code><code>&#10003; tests/integration/rpc.integration.test.ts - 3 tests

Test Files: 1 passed
Tests:      3 passed</code></code></pre><p>Those live tests verify things including:</p><pre><code><code>&#10003; Connect to the public RPC
&#10003; Read the latest block
&#10003; Read the official PONS reference token
&#10003; Verify the V1 factory path
&#10003; Verify the V2 factory path</code></code></pre><p>The important distinction is:</p><p><strong>Unit tests:</strong> does my code behave correctly?</p><p><strong>Integration tests:</strong> does my code behave correctly against the actual network and deployed contracts?</p><p>For a blockchain SDK, I want both.</p><div><hr></div><h2>The milestone is complete</h2><p>At this point, I consider the first SDK milestone complete.</p><pre><code><code>[x] Robinhood Chain connection
[x] Pons V1/V2 contract configuration
[x] Contract reads
[x] TokenLaunched decoding
[x] Chunked getLogs queries
[x] Launch queries
[x] Real onchain event fixtures
[x] 30/30 unit tests
[x] 3/3 live integration tests</code></code></pre><p>That&#8217;s enough for the foundation.</p><p>It isn&#8217;t the finished product.</p><p>That&#8217;s the point.</p><div><hr></div><h1>What&#8217;s next?</h1><p>The next problem is not another SDK feature.</p><p>It&#8217;s <strong>state</strong>.</p><p>Right now the architecture is:</p><pre><code><code>Robinhood Chain
      &#8595;
 Pons Events
      &#8595;
     SDK
      &#8595;
 Application</code></code></pre><p>The next version becomes:</p><pre><code><code>Robinhood Chain
      &#8595;
 Pons Events
      &#8595;
     SDK
      &#8595;
   Indexer
      &#8595;
  Database
      &#8595;
Queryable State</code></code></pre><p>The first indexer should remain deliberately small.</p><p>Start with:</p><p><code>TokenLaunched</code></p><p>Store the core information required to reconstruct launch history:</p><pre><code><code>token
deployer
pool
version
blockNumber
transactionHash
logIndex
timestamp</code></code></pre><p>Then make the indexing process:</p><p><strong>replayable + deterministic + idempotent</strong></p><p>That gives us a reliable historical foundation before adding more event types.</p><div><hr></div><h1>From launches to market state</h1><p>Once launch events are indexed, the next question becomes more interesting.</p><p>What happens after launch?</p><p>Pons&#8217;s onchain activity can be treated as an event stream.</p><p>Conceptually:</p><pre><code><code>TokenLaunched
      &#8595;
Pool Activity
      &#8595;
Swap Events
      &#8595;
State Changes
      &#8595;
Market State</code></code></pre><p>That opens the door to:</p><ul><li><p>token activity tracking</p></li><li><p>price history</p></li><li><p>volume</p></li><li><p>liquidity</p></li><li><p>launch velocity</p></li><li><p>pool activity</p></li><li><p>real-time monitoring</p></li><li><p>market analytics</p></li></ul><p>But those features belong above the data foundation.</p><p>First I want the state layer to be trustworthy.</p><div><hr></div><h1>Why I&#8217;m not building the bot yet</h1><p>It&#8217;s tempting to jump straight to a trading application.</p><p>I could build a scanner.</p><p>Then add a strategy.</p><p>Then connect execution.</p><p>But I&#8217;m deliberately resisting that sequence.</p><p>A trading system should not start with:</p><blockquote><p>&#8220;How do I make the bot trade?&#8221;</p></blockquote><p>It should start with:</p><blockquote><p>&#8220;Can I reliably understand what&#8217;s happening?&#8221;</p></blockquote><p>So my preferred progression is:</p><pre><code><code>Contracts
   &#8595;
Events
   &#8595;
State
   &#8595;
Data
   &#8595;
Analytics
   &#8595;
Strategy
   &#8595;
Execution</code></code></pre><p>That gives every later layer something solid to build on.</p><div><hr></div><h1>Why this fits my broader engineering work</h1><p>I&#8217;ve spent a lot of time working on trading systems where the hard problems aren&#8217;t always visible in the strategy.</p><p>They show up in:</p><ul><li><p>real-time data</p></li><li><p>event-driven architecture</p></li><li><p>state synchronization</p></li><li><p>concurrency</p></li><li><p>execution</p></li><li><p>risk</p></li><li><p>reconciliation</p></li><li><p>observability</p></li><li><p>recovery</p></li></ul><p>Building on Robinhood Chain gives me a different environment in which to apply the same systems thinking.</p><p>The underlying engineering problem is still familiar:</p><p><strong>turn a stream of events into reliable state, then build applications on top of that state.</strong></p><p>That&#8217;s the part I&#8217;m interested in.</p><div><hr></div><h1>What I want this project to become</h1><p>The long-term architecture looks something like:</p><pre><code><code>                 ROBINHOOD CHAIN
                        &#8595;
                  PONS CONTRACTS
                        &#8595;
                   EVENT STREAM
                        &#8595;
                       SDK
                        &#8595;
                     INDEXER
                        &#8595;
                   MARKET STATE
                        &#8595;
          &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
          &#8595;             &#8595;             &#8595;
      Analytics       Scanner      Research
          &#8595;             &#8595;             &#8595;
          &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                        &#8595;
                Strategy Engine
                        &#8595;
                   Risk Layer
                        &#8595;
                    Execution</code></code></pre><p>The bot, if there is one, sits at the bottom.</p><p>The data infrastructure comes first.</p><div><hr></div><h1>What the first milestone taught me</h1><p>The first lesson is simple:</p><p><strong>The interesting part isn&#8217;t the SDK itself.</strong></p><p>The interesting part is what becomes possible once raw protocol data can be consumed reliably.</p><p>A clean chain connection gives you access to the network.</p><p>A contract wrapper gives you access to protocol state.</p><p>Event decoding gives you structured activity.</p><p>Testing gives you confidence that the integration actually works.</p><p>And indexing turns those individual events into a system that can answer questions about the market over time.</p><p>That&#8217;s the foundation I&#8217;m building now.</p><div><hr></div><h1>Roadmap</h1><p>The current roadmap is:</p><pre><code><code>[x] Robinhood Chain client
[x] Pons V1/V2 factories
[x] Contract reads
[x] TokenLaunched decoding
[x] Historical launch queries
[x] Unit tests
[x] Live RPC integration tests

[ ] Historical indexer
[ ] Persistent launch state
[ ] Real-time event stream
[ ] Swap indexing
[ ] Token state
[ ] Market analytics
[ ] Scanner
[ ] Strategy research
[ ] Trading integration</code></code></pre><p>The roadmap is intentionally bottom-up.</p><p><strong>Infrastructure first.</strong></p><p>Applications later.</p><div><hr></div><h1>Final thought</h1><p>I didn&#8217;t start this project by asking:</p><blockquote><p>&#8220;What bot should I build?&#8221;</p></blockquote><p>I started with a more basic question:</p><blockquote><p><strong>&#8220;Can I build a reliable data layer for Pons on Robinhood Chain?&#8221;</strong></p></blockquote><p>The first answer is now yes.</p><p>The SDK can connect to the live network, interact with deployed Pons contracts, decode real launch events, and pass both local and live integration tests.</p><p>The next step is turning those events into persistent state.</p><p>From there, the interesting problems get much bigger.</p><p><strong>Events &#8594; state &#8594; analytics &#8594; strategy &#8594; execution.</strong></p><p>That&#8217;s where I&#8217;m going next.</p><p>No hype.</p><p>Just the infrastructure, the tests, the data, and what the system actually teaches me.</p>]]></content:encoded></item></channel></rss>