<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BornToWin</title>
    <description>The latest articles on DEV Community by BornToWin (@borntoup).</description>
    <link>https://dev.to/borntoup</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2177649%2F0b0b2de4-9e30-47c2-bace-9afd6201d26e.jpg</url>
      <title>DEV Community: BornToWin</title>
      <link>https://dev.to/borntoup</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/borntoup"/>
    <language>en</language>
    <item>
      <title>Building a Pons Launch Monitor on Robinhood Chain with TypeScript</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Thu, 10 Sep 2026 09:29:36 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-pons-launch-monitor-on-robinhood-chain-with-typescript-406i</link>
      <guid>https://dev.to/borntoup/building-a-pons-launch-monitor-on-robinhood-chain-with-typescript-406i</guid>
      <description>&lt;p&gt;&lt;em&gt;How to index Pons launches, decode onchain events, track token state, filter opportunities, send alerts, and build a reliable data layer for trading bots.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Pons launch monitor&lt;/strong&gt; sounds like a simple application:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev01"&lt;br&gt;
New Launch&lt;br&gt;
    ↓&lt;br&gt;
Display Token&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


But once the monitor becomes the data source for a **Pons sniper bot**, **Pons copy trading bot**, or trading terminal, reliability becomes much more important.

The useful architecture is:



```text id="plmdev02"
Robinhood Chain
      ↓
Pons Factory / Protocol Events
      ↓
Launch Indexer
      ↓
Event Decoder
      ↓
Token State
      ↓
Filters
      ↓
Persistent Storage
      ↓
Alerts / API
      ↓
Trading Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The current Pons documentation recommends reading directly from contracts and indexing protocol events as the onchain source of truth. The documented v1 integration starts with the factory's &lt;code&gt;TokenLaunched&lt;/code&gt; event and then indexes the corresponding pool's &lt;code&gt;Swap&lt;/code&gt; events. Pons v2 has a different lifecycle based on a bonding curve followed by graduation into a Uniswap v4 pool, so the monitor should be aware of the protocol version it is indexing.&lt;/p&gt;

&lt;p&gt;This article focuses on how I would structure that system in TypeScript.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Is a Pons Launch Monitor?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Pons launch monitor&lt;/strong&gt; continuously watches Robinhood Chain for new Pons launches and turns raw blockchain activity into structured information.&lt;/p&gt;

&lt;p&gt;Instead of forcing every downstream system to understand smart-contract events, the monitor exposes something simple:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;``&lt;code&gt;typescript id="plmdev03"&lt;br&gt;
interface PonsLaunch {&lt;br&gt;
  id: string;&lt;br&gt;
  tokenAddress:&lt;/code&gt;0x${string}&lt;code&gt;;&lt;br&gt;
  deployer:&lt;/code&gt;0x${string}`;&lt;/p&gt;

&lt;p&gt;poolAddress?: &lt;code&gt;0x${string}&lt;/code&gt;;&lt;br&gt;
  curveAddress?: &lt;code&gt;0x${string}&lt;/code&gt;;&lt;/p&gt;

&lt;p&gt;protocolVersion: "v1" | "v2";&lt;/p&gt;

&lt;p&gt;blockNumber: bigint;&lt;br&gt;
  transactionHash: &lt;code&gt;0x${string}&lt;/code&gt;;&lt;/p&gt;

&lt;p&gt;detectedAt: number;&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Now everything downstream can consume the same object:



```text id="plmdev04"
Pons Launch
   ├── Dashboard
   ├── Alert System
   ├── Sniper Bot
   ├── Copy Trading
   └── Analytics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Build the Monitor First?
&lt;/h2&gt;

&lt;p&gt;Trading systems need data.&lt;/p&gt;

&lt;p&gt;A sniper needs:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev05"&lt;br&gt;
new launch&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


A copy-trading system needs:



```text id="plmdev06"
token + current trading state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;An analytics system needs:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev07"&lt;br&gt;
historical launch + trade data&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


A trading terminal needs:



```text id="plmdev08"
live protocol activity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All four can use the same Pons data layer.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev09"&lt;br&gt;
                    Pons Data Layer&lt;br&gt;
                           │&lt;br&gt;
          ┌────────────────┼────────────────┐&lt;br&gt;
          ↓                ↓                ↓&lt;br&gt;
       Sniper            Copy           Analytics&lt;br&gt;
          │                │                │&lt;br&gt;
          └────────────────┼────────────────┘&lt;br&gt;
                           ↓&lt;br&gt;
                    Trading Terminal&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


That makes the launch monitor more than a notification tool.

It becomes infrastructure.

---

## Project Structure

A clean TypeScript project could look like:



```text id="plmdev10"
src/
├── chain/
│   └── client.ts
│
├── pons/
│   ├── factory.ts
│   ├── events.ts
│   ├── decoder.ts
│   └── state.ts
│
├── indexer/
│   ├── launch-indexer.ts
│   ├── checkpoint.ts
│   └── dedupe.ts
│
├── storage/
│   └── launches.ts
│
├── filters/
│   └── launch-filters.ts
│
├── alerts/
│   └── dispatcher.ts
│
├── api/
│   └── server.ts
│
└── main.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The important separation is:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev11"&lt;br&gt;
Blockchain&lt;br&gt;
   ↓&lt;br&gt;
Indexer&lt;br&gt;
   ↓&lt;br&gt;
Normalized Data&lt;br&gt;
   ↓&lt;br&gt;
Application&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


---

## 1. Connect to Robinhood Chain

Pons currently documents Robinhood Chain as chain ID `4663` and exposes a public RPC endpoint.

Using `viem`:



```typescript id="plmdev12"
import { createPublicClient, http } from "viem";

const client = createPublicClient({
  chain: {
    id: 4663,
    name: "Robinhood Chain",
    nativeCurrency: {
      name: "Ether",
      symbol: "ETH",
      decimals: 18,
    },
    rpcUrls: {
      default: {
        http: [
          "https://rpc.mainnet.chain.robinhood.com",
        ],
      },
    },
  },
  transport: http(),
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;```typescript id="plmdev13"&lt;br&gt;
const chainId = await client.getChainId();&lt;/p&gt;

&lt;p&gt;console.log({&lt;br&gt;
  chainId,&lt;br&gt;
});&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


For production, the RPC layer should also handle:



```text id="plmdev14"
timeouts
retries
backoff
rate limits
health checks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Do not let every part of the application call the RPC directly.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Define the Pons Factory
&lt;/h2&gt;

&lt;p&gt;For the current v1 documentation, the factory is the entry point for launch detection.&lt;/p&gt;

&lt;p&gt;Pons documents a &lt;code&gt;TokenLaunched&lt;/code&gt; event containing fields including the token, deployer, pair token, pool, launch configuration, position information, restriction end block, and initial buy amount.&lt;/p&gt;

&lt;p&gt;Define the event once:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```typescript id="plmdev15"&lt;br&gt;
import { parseAbiItem } from "viem";&lt;/p&gt;

&lt;p&gt;export const tokenLaunchedEvent = parseAbiItem(&lt;br&gt;
  "event TokenLaunched(address indexed token, address indexed deployer, address indexed dexFactory, address pairToken, address pool, uint256 dexId, uint256 launchConfigId, uint256 positionId, uint256 restrictionsEndBlock, uint256 initialBuyAmount)"&lt;br&gt;
);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Then keep the factory address in configuration.

Do not scatter protocol addresses across the codebase.

---

## 3. Read Launch Events

Once the client and event definition exist:



```typescript id="plmdev16"
const logs = await client.getLogs({
  address: PONS_FACTORY,
  event: tokenLaunchedEvent,
  fromBlock: startBlock,
  toBlock: "latest",
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now every returned log represents a potential launch record.&lt;/p&gt;

&lt;p&gt;Normalize it immediately.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;``&lt;code&gt;typescript id="plmdev17"&lt;br&gt;
function decodeLaunch(log: any): PonsLaunch {&lt;br&gt;
  return {&lt;br&gt;
    id:&lt;/code&gt;${log.transactionHash}:${log.logIndex}`,&lt;br&gt;
    tokenAddress: log.args.token,&lt;br&gt;
    deployer: log.args.deployer,&lt;br&gt;
    poolAddress: log.args.pool,&lt;br&gt;
    protocolVersion: "v1",&lt;br&gt;
    blockNumber: log.blockNumber,&lt;br&gt;
    transactionHash: log.transactionHash,&lt;br&gt;
    detectedAt: Date.now(),&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The actual type should be narrowed using the generated viem types rather than `any`.

---

## 4. Why the Log Index Matters

A transaction can emit multiple logs.

So:



```text id="plmdev18"
transaction hash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;alone is not always enough to identify one specific event.&lt;/p&gt;

&lt;p&gt;A better event identity is:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev19"&lt;br&gt;
transactionHash + logIndex&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Then:



```typescript id="plmdev20"
const id =
  `${transactionHash}:${logIndex}`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That creates a deterministic identifier for deduplication.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Build a Block-Based Indexer
&lt;/h2&gt;

&lt;p&gt;A production launch monitor should not repeatedly scan the entire chain.&lt;/p&gt;

&lt;p&gt;Use checkpoints.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev21"&lt;br&gt;
Start Block&lt;br&gt;
     ↓&lt;br&gt;
Process&lt;br&gt;
     ↓&lt;br&gt;
Checkpoint&lt;br&gt;
     ↓&lt;br&gt;
Next Block&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


A simple indexer loop:



```typescript id="plmdev22"
let lastProcessedBlock = await checkpoint.load();

const latest =
  await client.getBlockNumber();

for (
  let block = lastProcessedBlock + 1n;
  block &amp;lt;= latest;
  block++
) {
  await processBlock(block);
  await checkpoint.save(block);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The exact implementation should batch blocks rather than making a separate RPC request for every block.&lt;/p&gt;

&lt;p&gt;The important concept is persistent progress.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Batch Event Reads
&lt;/h2&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev23"&lt;br&gt;
Block 1 → RPC&lt;br&gt;
Block 2 → RPC&lt;br&gt;
Block 3 → RPC&lt;br&gt;
...&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


use ranges:



```text id="plmdev24"
Blocks 1–5000
      ↓
getLogs()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;```typescript id="plmdev25"&lt;br&gt;
const logs = await client.getLogs({&lt;br&gt;
  address: PONS_FACTORY,&lt;br&gt;
  event: tokenLaunchedEvent,&lt;br&gt;
  fromBlock: start,&lt;br&gt;
  toBlock: end,&lt;br&gt;
});&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Then process the returned events locally.

This usually reduces RPC overhead considerably.

---

## 7. Make the Indexer Restart-Safe

Suppose the process crashes after:



```text id="plmdev26"
Block 9,000,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The monitor should restart from the last successfully committed checkpoint.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev27"&lt;br&gt;
Saved:&lt;br&gt;
9,000,000&lt;/p&gt;

&lt;p&gt;Crash&lt;/p&gt;

&lt;p&gt;Restart:&lt;br&gt;
9,000,001&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The critical rule is:

&amp;gt; Save the checkpoint only after the corresponding data has been successfully persisted.

Otherwise you can mark a block as processed even though its launch records were never saved.

---

## 8. Deduplication

Even with checkpoints, duplicates can appear.

For every event:



```text id="plmdev28"
event ID
   ↓
database
   ↓
exists?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If it exists:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev29"&lt;br&gt;
skip&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


If it doesn't:



```text id="plmdev30"
insert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;```typescript id="plmdev31"&lt;br&gt;
const existing =&lt;br&gt;
  await repository.findById(eventId);&lt;/p&gt;

&lt;p&gt;if (existing) {&lt;br&gt;
  return;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;await repository.insert(launch);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


This is important for recovery and overlapping index ranges.

---

## 9. Token Address Is the Identity

A token name is not enough.

Pons explicitly warns that names and symbols can be copied and recommends checking the token address.

So:



```text id="plmdev32"
"PONZ"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;should never be your primary identifier.&lt;/p&gt;

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

&lt;p&gt;```text id="plmdev33"&lt;br&gt;
0x1234...&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Then enrich the token with:



```text id="plmdev34"
name
symbol
decimals
metadata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The address remains the identity.&lt;/p&gt;


&lt;h2&gt;
  
  
  10. Fetch Token Metadata
&lt;/h2&gt;

&lt;p&gt;Once a launch is detected:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev35"&lt;br&gt;
Launch&lt;br&gt;
  ↓&lt;br&gt;
Token Address&lt;br&gt;
  ↓&lt;br&gt;
ERC-20 Calls&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Typical calls:



```typescript id="plmdev36"
const name = await token.read.name();
const symbol = await token.read.symbol();
const decimals = await token.read.decimals();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Metadata should be considered enrichment.&lt;/p&gt;

&lt;p&gt;If metadata retrieval fails:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev37"&lt;br&gt;
Launch still exists.&lt;br&gt;
Metadata = unavailable.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Don't discard a valid onchain launch merely because an enrichment request failed.

---

## 11. Detect the Protocol Version

This is particularly important for Pons.

Current v1 documentation describes a pool-based launch model, with tokens launched directly into a WETH trading pool.

Pons v2 uses a different lifecycle:



```text id="plmdev38"
Launch
  ↓
Bonding Curve
  ↓
Curve Trading
  ↓
Graduation
  ↓
Uniswap v4 Pool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The v2 documentation states that the curve holds the supply until graduation and that the resulting pool is created at graduation.&lt;/p&gt;

&lt;p&gt;Therefore your monitor should not assume:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```typescript id="plmdev39"&lt;br&gt;
poolAddress !== undefined&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


means the token is currently trading in that pool.

The current trading venue is state-dependent.

---

## 12. Model Trading State

Create a normalized state:



```typescript id="plmdev40"
type TradingVenue =
  | "PONS_POOL"
  | "PONS_CURVE"
  | "UNISWAP_V4";

interface TradingState {
  venue: TradingVenue;
  active: boolean;
  poolAddress?: string;
  curveAddress?: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;```text id="plmdev41"&lt;br&gt;
Token&lt;br&gt;
  ↓&lt;br&gt;
Protocol Version&lt;br&gt;
  ↓&lt;br&gt;
Current State&lt;br&gt;
  ↓&lt;br&gt;
Trading Venue&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Now the trading bot doesn't care about the low-level protocol transition.

---

## 13. Monitor Pons v1 Swaps

For the current v1 integration, the documentation recommends registering each emitted pool and indexing its `Swap` events.

The flow is:



```text id="plmdev42"
TokenLaunched
      ↓
Pool Address
      ↓
Register Pool
      ↓
Pool Swap Events
      ↓
Trade Stream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That gives your launch database a second dimension:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev43"&lt;br&gt;
Launch&lt;br&gt;
  └── Trades&lt;br&gt;
      ├── Buy&lt;br&gt;
      ├── Sell&lt;br&gt;
      ├── Buy&lt;br&gt;
      └── Sell&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


---

## 14. Track Pons v2 Curve Activity

For v2, the monitor needs to understand the curve lifecycle.

Pons v2 documents:



```text id="plmdev44"
Create
  ↓
Trade the Curve
  ↓
Graduate
  ↓
Trade Uniswap v4 Pool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and explains that the curve is the initial trading venue before graduation.&lt;/p&gt;

&lt;p&gt;So the monitor should maintain:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev45"&lt;br&gt;
curve state&lt;br&gt;
graduation state&lt;br&gt;
current venue&lt;br&gt;
current pool&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


This avoids making incorrect assumptions when a token moves from the curve to Uniswap.

---

## 15. Track Launch Windows

For the current v1 integration, the launch event includes a `restrictionsEndBlock`, which can be persisted as part of the launch record.

Store:



```typescript id="plmdev46"
interface LaunchTiming {
  launchBlock: bigint;
  restrictionsEndBlock?: bigint;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then the application can calculate:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev47"&lt;br&gt;
current block&lt;br&gt;
    ↓&lt;br&gt;
restriction end block&lt;br&gt;
    ↓&lt;br&gt;
blocks remaining&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


This can feed:



```text id="plmdev48"
alerts
sniper evaluation
dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;without hard-coding the timing rules in multiple places.&lt;/p&gt;


&lt;h2&gt;
  
  
  16. Launch Filters
&lt;/h2&gt;

&lt;p&gt;A useful launch monitor needs filtering.&lt;/p&gt;

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

&lt;p&gt;```typescript id="plmdev49"&lt;br&gt;
interface LaunchFilter {&lt;br&gt;
  deployer?: string[];&lt;br&gt;
  tokenAllowlist?: string[];&lt;br&gt;
  tokenDenylist?: string[];&lt;br&gt;
  protocolVersion?: ("v1" | "v2")[];&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Then:



```text id="plmdev50"
New Launch
    ↓
Filter Engine
    ├── deployer
    ├── token
    ├── protocol
    └── current state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The result can be:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev51"&lt;br&gt;
MATCH&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


or:



```text id="plmdev52"
SKIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  17. Persistence
&lt;/h2&gt;

&lt;p&gt;A launch monitor needs a database or another durable store.&lt;/p&gt;

&lt;p&gt;At minimum:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev53"&lt;br&gt;
token_address&lt;br&gt;
deployer&lt;br&gt;
pool_address&lt;br&gt;
curve_address&lt;br&gt;
protocol_version&lt;br&gt;
launch_block&lt;br&gt;
transaction_hash&lt;br&gt;
detected_at&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


For trades:



```text id="plmdev54"
trade_id
token_address
pool_or_curve
trader
side
amount
transaction_hash
block_number
timestamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;```text id="plmdev55"&lt;br&gt;
Launch&lt;br&gt;
   ↓&lt;br&gt;
Trades&lt;br&gt;
   ↓&lt;br&gt;
Analytics&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


---

## 18. Alerts

Once a launch enters the system, publish an internal event:



```typescript id="plmdev56"
eventBus.emit(
  "pons.launch.detected",
  launch
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then several consumers can subscribe:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev57"&lt;br&gt;
pons.launch.detected&lt;br&gt;
       │&lt;br&gt;
       ├── Telegram&lt;br&gt;
       ├── Discord&lt;br&gt;
       ├── WebSocket&lt;br&gt;
       ├── Dashboard&lt;br&gt;
       └── Sniper&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


This is much cleaner than putting Telegram, dashboard, and trading logic directly into the indexer.

---

## 19. WebSocket Updates

A dashboard should not need to refresh constantly.

Use:



```text id="plmdev58"
Indexer
   ↓
Event Bus
   ↓
WebSocket
   ↓
Browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When a launch arrives:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev59"&lt;br&gt;
NEW LAUNCH&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


the UI can update immediately.

The same stream can later power a trading terminal.

---

## 20. API

Expose normalized data through an API.

For example:



```text id="plmdev60"
GET /launches
GET /launches/recent
GET /launches/:token
GET /launches/:token/trades
GET /launches/:token/state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A response can look like:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```json id="plmdev61"&lt;br&gt;
{&lt;br&gt;
  "token": "0x123...",&lt;br&gt;
  "deployer": "0x456...",&lt;br&gt;
  "protocolVersion": "v2",&lt;br&gt;
  "venue": "PONS_CURVE",&lt;br&gt;
  "launchBlock": "12345678",&lt;br&gt;
  "status": "ACTIVE"&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Now external applications can consume your monitor.

---

## 21. Monitoring Latency

A launch monitor that feeds a sniper needs measurable latency.

Track:



```text id="plmdev62"
Block received
      ↓
Event decoded
      ↓
Launch persisted
      ↓
Alert published
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;```text id="plmdev63"&lt;br&gt;
Block → Decode:     15 ms&lt;br&gt;
Decode → DB:         8 ms&lt;br&gt;
DB → Alert:          4 ms&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The numbers should come from your instrumentation.

Don't optimize based on assumptions.

---

## 22. Reorganization and Confirmation Strategy

A production indexer also needs to consider chain reorganization and confirmation policy.

A simple model is:



```text id="plmdev64"
Observed
   ↓
Pending
   ↓
Confirmed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The number of confirmations should be configurable.&lt;/p&gt;

&lt;p&gt;This lets you distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev65"&lt;br&gt;
fresh observation&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


from:



```text id="plmdev66"
stable indexed state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The appropriate policy depends on the application's risk tolerance.&lt;/p&gt;


&lt;h2&gt;
  
  
  23. Error Handling
&lt;/h2&gt;

&lt;p&gt;Do not treat every failure the same way.&lt;/p&gt;

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

&lt;p&gt;```text id="plmdev67"&lt;br&gt;
RPC timeout&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


is different from:



```text id="plmdev68"
invalid event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;which is different from:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev69"&lt;br&gt;
database failure&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Use explicit categories:



```typescript id="plmdev70"
type IndexerError =
  | "RPC_TIMEOUT"
  | "RPC_RATE_LIMIT"
  | "DECODE_ERROR"
  | "DATABASE_ERROR"
  | "CHECKPOINT_ERROR";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then apply appropriate recovery.&lt;/p&gt;


&lt;h2&gt;
  
  
  24. Recovery
&lt;/h2&gt;

&lt;p&gt;Suppose the monitor dies at:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev71"&lt;br&gt;
Block 10,000,000&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


On restart:



```text id="plmdev72"
Load checkpoint
      ↓
Resume indexing
      ↓
Deduplicate
      ↓
Continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That is much better than restarting from the beginning.&lt;/p&gt;

&lt;p&gt;Persistent checkpoints + deterministic IDs give you:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev73"&lt;br&gt;
restart safety&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


---

## 25. Connecting the Launch Monitor to a Pons Sniper

Once the monitor works, a sniper can subscribe to launch events:



```text id="plmdev74"
Pons Launch Monitor
        ↓
New Launch
        ↓
Sniper Strategy
        ↓
Risk
        ↓
Quote
        ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The monitor does not need to know:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev75"&lt;br&gt;
how much money to trade&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The sniper owns that decision.

---

## 26. Connecting It to Copy Trading

The same infrastructure can feed a copy-trading system.



```text id="plmdev76"
Pons Monitor
      ↓
Token State
      ↓
Source Wallet Activity
      ↓
Copy Strategy
      ↓
Risk
      ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is why I prefer a reusable data layer over building a separate monitor inside every bot.&lt;/p&gt;


&lt;h2&gt;
  
  
  27. Example End-to-End Flow
&lt;/h2&gt;

&lt;p&gt;A complete event can look like:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev77"&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;New block arrives
    ↓&lt;/li&gt;
&lt;li&gt;Factory event detected
    ↓&lt;/li&gt;
&lt;li&gt;TokenLaunched decoded
    ↓&lt;/li&gt;
&lt;li&gt;Launch ID created
    ↓&lt;/li&gt;
&lt;li&gt;Duplicate check
    ↓&lt;/li&gt;
&lt;li&gt;Launch persisted
    ↓&lt;/li&gt;
&lt;li&gt;Token metadata requested
    ↓&lt;/li&gt;
&lt;li&gt;Trading state resolved
    ↓&lt;/li&gt;
&lt;li&gt;Filters applied
    ↓&lt;/li&gt;
&lt;li&gt;Alert published
    ↓&lt;/li&gt;
&lt;li&gt;Dashboard updated
    ↓&lt;/li&gt;
&lt;li&gt;Sniper / copy strategy can evaluate
```
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every step is independently observable.&lt;/p&gt;




&lt;h2&gt;
  
  
  28. Keep the Monitor Independent From Strategy
&lt;/h2&gt;

&lt;p&gt;This architecture is important:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev78"&lt;br&gt;
                 Pons Launch Monitor&lt;br&gt;
                         │&lt;br&gt;
            ┌────────────┼────────────┐&lt;br&gt;
            ↓            ↓            ↓&lt;br&gt;
          Alerts       Sniper        Copy&lt;br&gt;
            │            │            │&lt;br&gt;
            └────────────┼────────────┘&lt;br&gt;
                         ↓&lt;br&gt;
                      Analytics&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The monitor reports facts.

The strategy interprets those facts.

That makes the system much easier to change.

---

## 29. Production Architecture

Eventually, the system can become:



```text id="plmdev79"
                         ROBINHOOD CHAIN
                                │
                                ▼
                          PONS INDEXER
                                │
               ┌────────────────┴────────────────┐
               ▼                                 ▼
        Launch Events                        Swap Events
               │                                 │
               └────────────────┬────────────────┘
                                ▼
                         Pons Data Store
                                │
             ┌──────────────────┼──────────────────┐
             ▼                  ▼                  ▼
          Dashboard           Alerts               API
             │                  │                  │
             └──────────────────┼──────────────────┘
                                ▼
                        Trading Strategies
                          │             │
                          ▼             ▼
                       Sniper          Copy
                          │             │
                          └──────┬──────┘
                                 ▼
                            Risk Engine
                                 ↓
                         Execution Engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now the launch monitor is the foundation of an entire trading stack.&lt;/p&gt;


&lt;h2&gt;
  
  
  30. Testing
&lt;/h2&gt;

&lt;p&gt;The monitor should have unit tests for:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev80"&lt;br&gt;
event decoding&lt;br&gt;
launch normalization&lt;br&gt;
deduplication&lt;br&gt;
checkpoint handling&lt;br&gt;
filtering&lt;br&gt;
metadata failure&lt;br&gt;
version detection&lt;br&gt;
reconnect behavior&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


For example:



```typescript id="plmdev81"
it("deduplicates the same launch event", async () =&amp;gt; {
  await indexEvent(event);
  await indexEvent(event);

  expect(await countLaunches()).toBe(1);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Integration tests should use a controlled environment and must not require real trading capital.&lt;/p&gt;


&lt;h2&gt;
  
  
  31. Security
&lt;/h2&gt;

&lt;p&gt;A launch monitor may not need private keys at all.&lt;/p&gt;

&lt;p&gt;That is an advantage.&lt;/p&gt;

&lt;p&gt;Keep the monitoring service separate from the signing service:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev82"&lt;br&gt;
Monitor&lt;br&gt;
   ↓&lt;br&gt;
Signal&lt;br&gt;
   ↓&lt;br&gt;
Trading Service&lt;br&gt;
   ↓&lt;br&gt;
Signer&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


If the monitor is compromised, it should not automatically expose trading credentials.

This separation becomes especially important once the monitor feeds live trading systems.

---

## 32. What I Would Build First

For version one:



```text id="plmdev83"
Pons Factory
     ↓
TokenLaunched
     ↓
Launch Decoder
     ↓
Persistent Store
     ↓
CLI / API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Version two:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev84"&lt;br&gt;
+&lt;br&gt;
Token Metadata&lt;br&gt;
+&lt;br&gt;
Pool / Curve State&lt;br&gt;
+&lt;br&gt;
Swap Tracking&lt;br&gt;
+&lt;br&gt;
Alerts&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Version three:



```text id="plmdev85"
+
Pons Sniper
+
Pons Copy Trading
+
Analytics
+
Trading Terminal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This keeps each stage independently useful.&lt;/p&gt;


&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Pons launch monitor&lt;/strong&gt; should not just display newly created tokens.&lt;/p&gt;

&lt;p&gt;It should create a reliable data layer:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev86"&lt;br&gt;
DETECT&lt;br&gt;
  ↓&lt;br&gt;
DECODE&lt;br&gt;
  ↓&lt;br&gt;
IDENTIFY&lt;br&gt;
  ↓&lt;br&gt;
RESOLVE STATE&lt;br&gt;
  ↓&lt;br&gt;
FILTER&lt;br&gt;
  ↓&lt;br&gt;
PERSIST&lt;br&gt;
  ↓&lt;br&gt;
ALERT&lt;br&gt;
  ↓&lt;br&gt;
SERVE&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Once that layer works, it can feed:



```text id="plmdev87"
Pons Sniper Bot
Pons Copy Trading Bot
Pons Analytics
Pons Trading Terminal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The key design principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Build the Pons monitor as infrastructure first; build trading strategies on top of it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gives you a reusable foundation instead of another isolated bot.&lt;/p&gt;

&lt;p&gt;And from a development perspective, that is the more valuable product:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;not just a Pons launch tracker, but a Pons data and trading-automation infrastructure layer for Robinhood Chain.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Need a Pons Launch Monitor Built?
&lt;/h2&gt;

&lt;p&gt;I build custom Robinhood Chain trading infrastructure, including:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```text id="plmdev88"&lt;br&gt;
Pons Launch Monitors&lt;br&gt;
Pons Sniper Bots&lt;br&gt;
Pons Copy Trading&lt;br&gt;
Pons Bundlers&lt;br&gt;
Trading Terminals&lt;br&gt;
Analytics&lt;br&gt;
Risk Engines&lt;br&gt;
Execution Systems&lt;br&gt;
Reconciliation&lt;/p&gt;

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


The system can be designed around the required Pons version, event sources, monitoring latency, filtering rules, alerting, APIs, dashboards, and downstream trading strategies.

---

## References

**Pons Documentation**
https://docs.ponsfamily.com/

**Pons v2 Documentation**
https://docs.ponsfamily.com/v2

**Pons Bundler Reference Implementation**
https://github.com/wooyang/pons-bundler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>typescript</category>
      <category>blockchain</category>
      <category>tradingbot</category>
      <category>robinhood</category>
    </item>
    <item>
      <title>Building a Pons Copy Trading Bot on Robinhood Chain with Python</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Wed, 09 Sep 2026 10:56:36 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-pons-copy-trading-bot-on-robinhood-chain-with-python-5824</link>
      <guid>https://dev.to/borntoup/building-a-pons-copy-trading-bot-on-robinhood-chain-with-python-5824</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical implementation architecture for monitoring wallets, decoding trades, applying copy rules, sizing positions, executing trades, and reconciling on-chain state.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Pons copy trading bot&lt;/strong&gt; watches a source wallet, detects supported trading activity, decides whether the trade should be copied, and executes a separate position from the follower wallet.&lt;/p&gt;

&lt;p&gt;The simple version looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Wallet
      ↓
Detect Trade
      ↓
Copy Trade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful implementation looks more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Wallet
      ↓
Block / Event Monitor
      ↓
Trade Decoder
      ↓
Copy Strategy
      ↓
Risk Engine
      ↓
Position Sizing
      ↓
Fresh Quote
      ↓
Pons Execution
      ↓
Transaction Monitor
      ↓
Portfolio
      ↓
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pons is a launch-and-trade application on Robinhood Chain, and its current documentation describes live token trading through each token's own pool.&lt;/p&gt;

&lt;p&gt;The goal of this article is to show how I would structure a &lt;strong&gt;Pons copy trading bot&lt;/strong&gt; as a real automation system rather than a script that blindly mirrors wallet transactions.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a Pons Copy Trading Bot?
&lt;/h2&gt;

&lt;p&gt;A Pons copy trading bot monitors one or more wallets and converts their supported trades into signals.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trader Wallet
     ↓
BUY Token A
     ↓
Copy Engine
     ↓
Risk Check
     ↓
Follower Wallet
     ↓
BUY Token A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the follower does not have to copy the transaction exactly.&lt;/p&gt;

&lt;p&gt;It can apply its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;copy ratio&lt;/li&gt;
&lt;li&gt;maximum position&lt;/li&gt;
&lt;li&gt;slippage&lt;/li&gt;
&lt;li&gt;token filters&lt;/li&gt;
&lt;li&gt;exposure limits&lt;/li&gt;
&lt;li&gt;signal-age limits&lt;/li&gt;
&lt;li&gt;gas reserve&lt;/li&gt;
&lt;li&gt;emergency stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the difference between &lt;strong&gt;transaction replication&lt;/strong&gt; and &lt;strong&gt;copy-trading infrastructure&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Architecture Matters
&lt;/h2&gt;

&lt;p&gt;The source wallet controls only the signal.&lt;/p&gt;

&lt;p&gt;Your system should control the money.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOURCE
  ↓
OBSERVATION
  ↓
STRATEGY
  ↓
RISK
  ↓
EXECUTION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means the source wallet should never directly determine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;how much you buy
how much you risk
which tokens you accept
how much slippage you tolerate
how many positions you can hold
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are follower-side decisions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Architecture
&lt;/h2&gt;

&lt;p&gt;I would separate the implementation into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bot/
├── monitor/
│   └── wallet_monitor.py
├── decoder/
│   └── trade_decoder.py
├── strategy/
│   └── copy_strategy.py
├── risk/
│   └── risk_engine.py
├── sizing/
│   └── position_sizer.py
├── execution/
│   └── pons_executor.py
├── portfolio/
│   └── position_manager.py
├── reconciliation/
│   └── reconciler.py
└── engine.py

config/
├── wallets.json
└── default.yaml

tests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact structure can differ, but the separation should remain.&lt;/p&gt;

&lt;p&gt;A monitor should monitor.&lt;/p&gt;

&lt;p&gt;An executor should execute.&lt;/p&gt;

&lt;p&gt;A portfolio manager should track positions.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Connect to Robinhood Chain
&lt;/h2&gt;

&lt;p&gt;Robinhood Chain mainnet currently uses chain ID &lt;code&gt;4663&lt;/code&gt; and ETH as its native gas asset.&lt;/p&gt;

&lt;p&gt;A minimal Python connection can start with:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;rpc_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RH_RPC_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;web3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Web3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HTTPProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rpc_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_connected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to connect to Robinhood Chain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Connected:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_connected&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chain ID:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chain_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important production rule is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not assume the RPC is healthy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;timeouts
retries
backoff
health checks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction reverted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They are not the same failure.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Configure Source Wallets
&lt;/h2&gt;

&lt;p&gt;The first useful configuration is a list of source wallets.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wallets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xSourceWallet..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alpha-trader"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"copy_ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"max_position_eth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration gives the system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wallet identity
copy ratio
position limit
enable/disable state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A production implementation should also support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;per-wallet risk
priority
score
token filters
daily limits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Monitor New Blocks
&lt;/h2&gt;

&lt;p&gt;One practical approach is block polling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;last_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block_number&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;current_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;block_number&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_block&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;last_block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;block_number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;last_block&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;current_block&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;process_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;last_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_block&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The monitor's job is to identify transactions involving the source wallet.&lt;/p&gt;

&lt;p&gt;It should not immediately execute trades.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Block
  ↓
Source wallet transaction
  ↓
Candidate transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then hand that transaction to the decoder.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Detect Source Wallet Activity
&lt;/h2&gt;

&lt;p&gt;A source wallet may produce many types of transactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ETH transfer
Token transfer
Approval
Launch
Buy
Sell
Other contract call
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The monitor should only forward transactions that could represent a supported trade.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_candidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source_wallet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;source_wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is only the first filter.&lt;/p&gt;

&lt;p&gt;You still need to inspect the receipt and contract interaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Decode the Actual Trade
&lt;/h2&gt;

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

&lt;p&gt;A transaction alone may not tell you the complete economic action.&lt;/p&gt;

&lt;p&gt;The decoder should inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction input
receipt
logs
Transfer events
router interaction
token addresses
amounts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The normalized output might look like:&lt;br&gt;
&lt;/p&gt;

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


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SourceTrade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;trade_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BUY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;amount_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;amount_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;tx_hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;block_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the strategy layer doesn't need to know anything about raw blockchain logs.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Deduplicate Trades
&lt;/h2&gt;

&lt;p&gt;The same transaction may be observed more than once.&lt;/p&gt;

&lt;p&gt;This can happen after:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC reconnect
process restart
polling overlap
event + polling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So generate a deterministic ID.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;trade_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;chain_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tx_hash&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trade_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trade_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trade
 ↓
Registry
 ↓
Seen?
 ├── YES → ignore
 └── NO  → evaluate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Duplicate prevention is one of the most important pieces of copy-trading infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Copy Strategy
&lt;/h2&gt;

&lt;p&gt;Now we have a real trade.&lt;/p&gt;

&lt;p&gt;The next question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should the follower copy it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create a strategy function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SourceTrade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BUY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;BLOCKED_TOKENS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The production version can add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;token allowlist
token denylist
minimum trade size
maximum trade size
source-wallet score
trade age
liquidity
existing position
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important thing is to keep the rules configurable.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Copy Ratio
&lt;/h2&gt;

&lt;p&gt;A simple copy strategy might use a percentage of the source trade.&lt;/p&gt;

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

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

Copy ratio:
10%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Follower:
0.05 ETH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using integer arithmetic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;BPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10_000&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;copy_amount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;source_amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;copy_ratio_bps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;source_amount&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;copy_ratio_bps&lt;/span&gt;
        &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;BPS&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids floating-point calculations.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Add a Maximum Position
&lt;/h2&gt;

&lt;p&gt;Even if the copy calculation says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.08 ETH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the strategy might only allow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.02 ETH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;proportional_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_position&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final process becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Trade
    ↓
Copy Ratio
    ↓
Maximum Position
    ↓
Risk Limits
    ↓
Final Position Size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is much safer than blindly copying source trade size.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Signal Freshness
&lt;/h2&gt;

&lt;p&gt;Copy trading has a latency problem.&lt;/p&gt;

&lt;p&gt;The source transaction may already be on-chain before the follower detects it.&lt;/p&gt;

&lt;p&gt;So every signal should have an age:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;trade_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;trade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trade_age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_SIGNAL_AGE_SECONDS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipeline becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Trade
      ↓
Detection
      ↓
Age Check
      ↓
Fresh?
   ├── NO → SKIP
   └── YES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A stale signal can produce a completely different execution outcome from the original trade.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Risk Engine
&lt;/h2&gt;

&lt;p&gt;The copy strategy should not have direct permission to spend funds.&lt;/p&gt;

&lt;p&gt;Add a risk layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RiskEngine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;wallet_balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invalid amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_POSITION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;position too large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wallet_balance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;GAS_RESERVE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;insufficient balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;approved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The architecture is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Trade
     ↓
Copy Strategy
     ↓
Risk Engine
     ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That separation is important.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Gas Reserve
&lt;/h2&gt;

&lt;p&gt;Never use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wallet balance = trading capital
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wallet balance
     ↓
gas reserve
     ↓
spendable balance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;spendable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;wallet_balance&lt;/span&gt;
    &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;gas_reserve&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;spendable&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No spendable balance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The risk engine should reject a trade if the gas reserve would be violated.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Fresh Pons Quote
&lt;/h2&gt;

&lt;p&gt;A follower should calculate its own current quote.&lt;/p&gt;

&lt;p&gt;Do not simply assume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source execution price
=
follower execution price
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pons currently documents token trading through each token's live pool, so the follower should evaluate current execution conditions rather than blindly copying the source's historical price.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Trade
      ↓
Current Pons State
      ↓
Fresh Quote
      ↓
Expected Output
      ↓
Slippage
      ↓
Follower Transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have a Pons-specific quote implementation, reuse it.&lt;/p&gt;

&lt;p&gt;Don't create a second pricing engine with an approximate formula.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Minimum Output
&lt;/h2&gt;

&lt;p&gt;A buy should define an acceptable execution boundary.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;expected_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens_out&lt;/span&gt;

&lt;span class="n"&gt;min_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;expected_out&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10_000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;slippage_bps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;10_000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected Output
      ↓
Slippage
      ↓
Minimum Output
      ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact formula should match the protocol's token decimals and contract behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  15. Pons Execution Layer
&lt;/h2&gt;

&lt;p&gt;Keep protocol-specific execution in a dedicated class:&lt;br&gt;
&lt;/p&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;buy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;amount_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;min_tokens_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy layer should never need to understand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nonce
gas
raw transaction
private-key signing
RPC broadcasting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should only submit an execution request.&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Transaction State Machine
&lt;/h2&gt;

&lt;p&gt;A copied trade needs explicit state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SIGNAL_RECEIVED
      ↓
DECODED
      ↓
STRATEGY_APPROVED
      ↓
RISK_APPROVED
      ↓
QUOTED
      ↓
PREPARED
      ↓
SIGNED
      ↓
SUBMITTED
      ↓
PENDING
      ├── CONFIRMED
      ├── REVERTED
      └── UNKNOWN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This state should be persisted.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Execution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;trade_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;tx_hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;amount_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the system can recover after a restart.&lt;/p&gt;




&lt;h2&gt;
  
  
  17. Never Blindly Retry Timeouts
&lt;/h2&gt;

&lt;p&gt;A dangerous pattern is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC timeout
   ↓
retry transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original transaction might already exist.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC timeout
   ↓
Check transaction state
   ↓
Reconcile
   ↓
Decide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UNKNOWN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don't know yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It should not mean:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It failed.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  18. Nonce Management
&lt;/h2&gt;

&lt;p&gt;For each follower wallet, use a single nonce-management strategy.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wallet
  ↓
Nonce Manager
  ↓
Transaction A
Transaction B
Transaction C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not let:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;copy strategy
retry worker
sell worker
transfer worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;all manage the same wallet nonce independently.&lt;/p&gt;

&lt;p&gt;That creates race conditions.&lt;/p&gt;




&lt;h2&gt;
  
  
  19. Portfolio Tracking
&lt;/h2&gt;

&lt;p&gt;Once a copy trade confirms, create or update a follower position.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;entry_amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;entry_tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trade
 ↓
Receipt
 ↓
Actual Token Balance
 ↓
Position
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not simply record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expected token output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as the actual position.&lt;/p&gt;




&lt;h2&gt;
  
  
  20. Copying Sells
&lt;/h2&gt;

&lt;p&gt;Buy copying is only half the problem.&lt;/p&gt;

&lt;p&gt;Suppose the source does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY Token A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELL 50% Token A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The follower needs its own sell policy.&lt;/p&gt;

&lt;p&gt;Possible models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sell 50% of follower position
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sell the same token quantity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reduce follower exposure to a target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good architecture keeps this in the copy strategy.&lt;/p&gt;




&lt;h2&gt;
  
  
  21. Reconciliation
&lt;/h2&gt;

&lt;p&gt;Reconciliation compares local state with the chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOCAL POSITION
      ↕
RECONCILIATION
      ↕
CHAIN STATE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction receipt
token balance
native balance
position state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run reconciliation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;after execution
after restart
after timeout
after reconnect
periodically
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what turns a long-running bot from an unreliable process into recoverable infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  22. Restart Recovery
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source trade detected
      ↓
Risk approved
      ↓
Transaction submitted
      ↓
Process crashes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After restart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load state
    ↓
Find pending execution
    ↓
Query blockchain
    ↓
Reconcile
    ↓
Continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot should not simply start from an empty in-memory state.&lt;/p&gt;




&lt;h2&gt;
  
  
  23. Paper Trading
&lt;/h2&gt;

&lt;p&gt;Before enabling live execution, build paper trading.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;PAPER_TRADING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PaperExecutionResult&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system should still perform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;monitoring
decoding
strategy
risk
position sizing
quote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but not broadcast a transaction.&lt;/p&gt;

&lt;p&gt;That allows you to validate the strategy before risking capital.&lt;/p&gt;




&lt;h2&gt;
  
  
  24. Emergency Stop
&lt;/h2&gt;

&lt;p&gt;A production bot should always have a kill switch.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;STOP_TRADING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Trading disabled by emergency stop&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible triggers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;manual stop
daily loss limit
RPC instability
unexpected execution behavior
too many failed transactions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The emergency stop should block &lt;strong&gt;new entries&lt;/strong&gt; while allowing reconciliation and reporting to continue.&lt;/p&gt;




&lt;h2&gt;
  
  
  25. Observability
&lt;/h2&gt;

&lt;p&gt;Track the complete funnel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source Trades
      ↓
Decoded Trades
      ↓
Eligible Trades
      ↓
Risk Approved
      ↓
Execution Submitted
      ↓
Confirmed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trades detected:       250
Trades decoded:        231
Signals accepted:       42
Risk rejected:          17
Submitted:              25
Confirmed:              22
Reverted:                2
Pending:                 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells you where the system is actually losing opportunities.&lt;/p&gt;




&lt;h2&gt;
  
  
  26. Latency Measurements
&lt;/h2&gt;

&lt;p&gt;For copy trading, measure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source transaction
        ↓
     detection
        ↓
     decoding
        ↓
     strategy
        ↓
       risk
        ↓
      quote
        ↓
    submission
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Detection:       80 ms
Decode:          15 ms
Strategy:         4 ms
Risk:             3 ms
Quote:           20 ms
Preparation:     18 ms
Submission:      30 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you know which component should be optimized.&lt;/p&gt;

&lt;p&gt;Without this instrumentation, latency discussions are mostly guesswork.&lt;/p&gt;




&lt;h2&gt;
  
  
  27. Example End-to-End Flow
&lt;/h2&gt;

&lt;p&gt;A complete copy event might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Source wallet buys Token A
                ↓
2. Block monitor detects transaction
                ↓
3. Decoder identifies Pons trade
                ↓
4. Opportunity registry checks duplication
                ↓
5. Copy strategy approves
                ↓
6. Signal freshness check passes
                ↓
7. Position size calculated
                ↓
8. Risk engine approves
                ↓
9. Fresh quote calculated
                ↓
10. minTokensOut calculated
                ↓
11. Transaction prepared
                ↓
12. Transaction signed
                ↓
13. Transaction submitted
                ↓
14. Receipt monitored
                ↓
15. Position created
                ↓
16. Reconciliation verifies state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the complete product.&lt;/p&gt;




&lt;h2&gt;
  
  
  28. CLI
&lt;/h2&gt;

&lt;p&gt;A simple interface could expose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py connect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py monitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py reconcile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py portfolio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And live trading should have explicit safety gates.&lt;/p&gt;

&lt;p&gt;A useful default is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAPER / DRY RUN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with live execution requiring explicit configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  29. Production Project Structure
&lt;/h2&gt;

&lt;p&gt;The final project can evolve into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bot/
├── monitor/
│   ├── block_monitor.py
│   └── wallet_tracker.py
│
├── decoder/
│   ├── trade_decoder.py
│   └── swap_classifier.py
│
├── strategy/
│   ├── copy_strategy.py
│   ├── filters.py
│   └── sizing.py
│
├── risk/
│   └── risk_engine.py
│
├── execution/
│   ├── pons_executor.py
│   ├── nonce_manager.py
│   └── transaction_manager.py
│
├── portfolio/
│   ├── positions.py
│   └── pnl.py
│
├── reconciliation/
│   └── reconciler.py
│
└── engine.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure also makes future strategy development much easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  30. From Copy Trading to Multiple Strategies
&lt;/h2&gt;

&lt;p&gt;Once the execution engine exists, copy trading becomes one strategy.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Pons Trading Engine
                          │
           ┌──────────────┼──────────────┐
           ↓              ↓              ↓
        Sniper           Copy         Momentum
        Strategy        Strategy       Strategy
           └──────────────┼──────────────┘
                          ↓
                      Risk Engine
                          ↓
                    Execution Engine
                          ↓
                     Robinhood Chain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the architecture I would build toward.&lt;/p&gt;

&lt;p&gt;The execution engine should be reusable.&lt;/p&gt;




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

&lt;p&gt;A &lt;strong&gt;Pons copy trading bot&lt;/strong&gt; is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;watch wallet
   ↓
copy transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MONITOR
   ↓
DECODE
   ↓
FILTER
   ↓
SIZE
   ↓
MANAGE RISK
   ↓
QUOTE
   ↓
EXECUTE
   ↓
MONITOR
   ↓
RECONCILE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference matters.&lt;/p&gt;

&lt;p&gt;The source wallet provides a signal.&lt;/p&gt;

&lt;p&gt;The follower system controls the decision.&lt;/p&gt;

&lt;p&gt;The blockchain determines the actual result.&lt;/p&gt;

&lt;p&gt;And reconciliation keeps the application's state aligned with reality.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Product Opportunity
&lt;/h2&gt;

&lt;p&gt;Once this execution layer works, it can support more than copy trading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pons Bundler
      ↓
Pons Sniper Bot
      ↓
Pons Copy Trading Bot
      ↓
Pons Launch Monitor
      ↓
Pons Trading Terminal
      ↓
Stock Token Arbitrage Bot
      ↓
Stock Token Trading Bot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The common foundation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data
 ↓
Strategy
 ↓
Risk
 ↓
Execution
 ↓
Monitoring
 ↓
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the part I care about most.&lt;/p&gt;

&lt;p&gt;Not just making a bot that can send a transaction.&lt;/p&gt;

&lt;p&gt;Building &lt;strong&gt;reliable trading infrastructure around a specific protocol&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Need a Pons Copy Trading Bot?
&lt;/h2&gt;

&lt;p&gt;I build custom trading automation for Robinhood Chain, including:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pons Copy Trading
Pons Sniper Bots
Pons Bundlers
Trading Automation
Risk Engines
Execution Systems
Transaction Monitoring
Portfolio / Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation should be designed around the client's strategy, wallet configuration, execution requirements, and risk controls rather than a generic one-size-fits-all bot.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pons documentation:&lt;/strong&gt; &lt;a href="https://docs.ponsfamily.com/" rel="noopener noreferrer"&gt;https://docs.ponsfamily.com/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Pons V2 documentation:&lt;/strong&gt; &lt;a href="https://docs.ponsfamily.com/v2" rel="noopener noreferrer"&gt;https://docs.ponsfamily.com/v2&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Pons bundler implementation:&lt;/strong&gt; &lt;a href="https://github.com/wooyang/pons-bundler" rel="noopener noreferrer"&gt;https://github.com/wooyang/pons-bundler&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>robinhood</category>
      <category>tradingbot</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Building a Pons Bundler on Robinhood Chain with TypeScript</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Tue, 08 Sep 2026 09:50:12 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-pons-bundler-on-robinhood-chain-with-typescript-432a</link>
      <guid>https://dev.to/borntoup/building-a-pons-bundler-on-robinhood-chain-with-typescript-432a</guid>
      <description>&lt;p&gt;Building a &lt;strong&gt;Pons bundler&lt;/strong&gt; on Robinhood Chain is less about sending multiple transactions and more about coordinating an entire launch workflow reliably.&lt;/p&gt;

&lt;p&gt;A useful open-source implementation is &lt;a href="https://github.com/wooyang/pons-bundler" rel="noopener noreferrer"&gt;&lt;code&gt;wooyang/pons-bundler&lt;/code&gt;&lt;/a&gt;, a TypeScript CLI for Pons v2 on Robinhood Chain.&lt;/p&gt;

&lt;p&gt;The project calls &lt;code&gt;launchAndBuy&lt;/code&gt;, registers buyer wallets for the launch flow, and submits additional curve buys in parallel. It also includes wallet generation, funding, dry-run execution, buying, selling, and sweeping.&lt;/p&gt;

&lt;p&gt;This article walks through the architecture and the engineering decisions behind a production-oriented Pons launch-automation system.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a Pons Bundler?
&lt;/h2&gt;

&lt;p&gt;First, an important distinction.&lt;/p&gt;

&lt;p&gt;A Pons bundler is &lt;strong&gt;not an ERC-4337 bundler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The referenced implementation describes Robinhood Chain as FCFS and notes that there is no atomic multi-signer transaction. The launch and initial buy happen in one transaction, while additional buyer wallets submit separate transactions targeting the same launch window.&lt;/p&gt;

&lt;p&gt;The execution model is therefore closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Pons Launch
                        │
                        ▼
                  launchAndBuy()
                        │
              ┌─────────┴─────────┐
              │                   │
        Master Wallet       Token + Curve
                                  │
                    ┌─────────────┼─────────────┐
                    ▼             ▼             ▼
                 Wallet A      Wallet B      Wallet C
                    │             │             │
                    └─────────────┼─────────────┘
                                  ▼
                         Parallel Buy Txs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is to coordinate execution, not to create a fake notion of atomicity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;A clean Pons bundler can separate the application into several layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLI
 │
 ├── status
 ├── wallets
 ├── launch
 ├── buy
 ├── sell
 └── sweep
       │
       ▼
Execution Layer
 │
 ├── launch orchestration
 ├── wallet coordination
 ├── quote calculation
 └── transaction handling
       │
       ▼
Pons Protocol Layer
 │
 ├── Factory
 ├── LaunchAndBuy
 ├── Curve
 └── Token
       │
       ▼
Robinhood Chain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repository is organized as a TypeScript CLI with its main library entry point under &lt;code&gt;src/index.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The separation matters because CLI code should not contain all of your blockchain logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Connecting to Robinhood Chain
&lt;/h2&gt;

&lt;p&gt;The first requirement is an RPC connection.&lt;/p&gt;

&lt;p&gt;A basic configuration can look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonRpcProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonRpcProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RH_RPC_URL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repository recommends using a paid RPC when possible because the public RPC is rate-limited.&lt;/p&gt;

&lt;p&gt;For a production service, I would add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC
 ├── timeout
 ├── retry policy
 ├── health checks
 └── fallback provider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to distinguish an RPC failure from a blockchain transaction failure.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does not mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction reverted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your execution engine needs to understand the difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contract Configuration
&lt;/h2&gt;

&lt;p&gt;The repository interacts with a Pons factory and launch-and-buy contract on Robinhood Chain. It documents the relevant contract addresses in its README.&lt;/p&gt;

&lt;p&gt;Instead of scattering addresses throughout the codebase, I prefer a protocol configuration object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PonsConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;launchAndBuy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;rpcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then initialize it once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PonsConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PONS_FACTORY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;launchAndBuy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PONS_LAUNCH_AND_BUY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;rpcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RH_RPC_URL&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes upgrades easier and reduces configuration mistakes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check &lt;code&gt;canLaunch&lt;/code&gt; Before Spending Gas
&lt;/h2&gt;

&lt;p&gt;One of the best ideas in the reference implementation is the &lt;code&gt;status&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;It reads the protocol's &lt;code&gt;canLaunch&lt;/code&gt; state before attempting a launch.&lt;/p&gt;

&lt;p&gt;The workflow should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;status
  │
  ├── canLaunch = false
  │       └── stop
  │
  └── canLaunch = true
          └── continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canLaunch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;canLaunch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;canLaunch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Pons launch is currently unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a general rule for blockchain automation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read protocol state before executing state-changing transactions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do not hard-code the assumption that a launch operation is always available.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wallet Management
&lt;/h2&gt;

&lt;p&gt;A multi-wallet application needs a dedicated wallet-management layer.&lt;/p&gt;

&lt;p&gt;The reference project includes commands for generating, funding, listing, and sweeping buyer wallets.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run pons &lt;span class="nt"&gt;--&lt;/span&gt; wallets generate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--count&lt;/span&gt; 8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out&lt;/span&gt; wallets.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting architecture is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Master Wallet
      │
      ├── fund
      │
      ▼
Buyer Wallet A
Buyer Wallet B
Buyer Wallet C
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each wallet should have explicit state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BuyerWallet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;encryptedKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;READY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FUNDED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact storage model can vary, but the key is to keep wallet management independent from execution strategy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Protect Private Keys
&lt;/h2&gt;

&lt;p&gt;A wallet file containing private keys is effectively a financial credential store.&lt;/p&gt;

&lt;p&gt;The reference repository keeps &lt;code&gt;wallets.json&lt;/code&gt; gitignored and explicitly warns not to commit it.&lt;/p&gt;

&lt;p&gt;For production infrastructure, I would prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Encrypted storage
       ↓
Wallet service
       ↓
Signing operation
       ↓
Transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than passing raw private keys around the application.&lt;/p&gt;

&lt;p&gt;A useful rule is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Private key
    ↓
Signer
    ↓
Signed transaction
    ↓
Broadcast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The private key should disappear from the rest of the application boundary.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Pons Launch Flow
&lt;/h2&gt;

&lt;p&gt;The key operation in the reference implementation is &lt;code&gt;launchAndBuy&lt;/code&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchAndBuy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tokenConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;launchConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;initialBuy&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The launch flow can be represented as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Validate
   ↓
Quote
   ↓
Build transaction
   ↓
Sign
   ↓
Broadcast
   ↓
Wait for receipt
   ↓
Read resulting state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is not the single contract call.&lt;/p&gt;

&lt;p&gt;It is everything around it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dry Run First
&lt;/h2&gt;

&lt;p&gt;A useful feature in the repository is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The README documents dry-run execution as a way to simulate the launch flow without broadcasting the transaction.&lt;/p&gt;

&lt;p&gt;This should become a standard development mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Execution
                    │
          ┌─────────┴─────────┐
          ▼                   ▼
       Dry Run              Live
          │                   │
      simulate            broadcast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before a live transaction, validate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ launch allowed
✓ wallets available
✓ wallet balances sufficient
✓ parameters valid
✓ quote available
✓ gas reserve available
✓ slippage configured
✓ contracts configured
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only then broadcast.&lt;/p&gt;




&lt;h2&gt;
  
  
  Curve Quotes
&lt;/h2&gt;

&lt;p&gt;Pons v2 uses a curve-based pricing model.&lt;/p&gt;

&lt;p&gt;That means you cannot treat the price as a static number.&lt;/p&gt;

&lt;p&gt;A buy changes the curve.&lt;/p&gt;

&lt;p&gt;The repository calculates &lt;code&gt;minTokensOut&lt;/code&gt; using curve reserve information and fees, while noting that parallel buys can move the curve.&lt;/p&gt;

&lt;p&gt;A simplified model looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current reserves
       │
       ▼
   curve quote
       │
       ▼
expected tokens
       │
       ▼
minimum tokens out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getBuyQuote&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;amountIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minTokensOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nf"&gt;applySlippage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokensOut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slippageBps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important value is not only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tokensOut
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minTokensOut
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives the transaction a defined execution boundary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Slippage Protection
&lt;/h2&gt;

&lt;p&gt;Automated execution should never blindly accept whatever output the transaction receives.&lt;/p&gt;

&lt;p&gt;A configuration might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BuyConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;amountIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;slippageBps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minTokensOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokensOut&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
  &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;slippageBps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual implementation should use the protocol's precise integer arithmetic and decimals.&lt;/p&gt;

&lt;p&gt;The principle is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected output
      ↓
Slippage boundary
      ↓
Transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts slippage from a UI preference into an explicit risk parameter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multiple Buyer Wallets
&lt;/h2&gt;

&lt;p&gt;The reference implementation supports registering buyer wallets for the launch workflow and then submitting their curve buys separately. It documents a maximum of 32 buyer wallets for this flow.&lt;/p&gt;

&lt;p&gt;The important architecture is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Master launch
      │
      ├── Wallet A → buy
      ├── Wallet B → buy
      ├── Wallet C → buy
      └── Wallet D → buy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are separate transactions.&lt;/p&gt;

&lt;p&gt;Therefore, the application should track each one independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Execution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;READY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SUBMITTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CONFIRMED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REVERTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is much more robust than having one global:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;launchStatus = SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Parallel Transaction Submission
&lt;/h2&gt;

&lt;p&gt;Sequential execution looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wallet A
   ↓
wait
   ↓
Wallet B
   ↓
wait
   ↓
Wallet C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parallel submission can instead prepare transactions independently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Launch Window
                  │
       ┌──────────┼──────────┐
       ▼          ▼          ▼
     Buy A      Buy B      Buy C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repository explicitly submits the additional curve buys in parallel.&lt;/p&gt;

&lt;p&gt;But parallel submission does &lt;strong&gt;not&lt;/strong&gt; create deterministic ordering.&lt;/p&gt;

&lt;p&gt;The network still decides transaction ordering and inclusion.&lt;/p&gt;

&lt;p&gt;Therefore, every transaction needs its own state machine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Transaction State Machine
&lt;/h2&gt;

&lt;p&gt;A useful model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED
   ↓
SIGNED
   ↓
SUBMITTED
   ↓
PENDING
   ├── CONFIRMED
   ├── REVERTED
   └── UNKNOWN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TxStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CREATED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SIGNED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SUBMITTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CONFIRMED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REVERTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UNKNOWN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the monitoring layer can periodically query the chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receipt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransactionReceipt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;txHash&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CONFIRMED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REVERTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That small distinction becomes extremely important when a process crashes or an RPC request times out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gas Management
&lt;/h2&gt;

&lt;p&gt;A buyer wallet needs more than the exact amount intended for the purchase.&lt;/p&gt;

&lt;p&gt;It also needs a gas reserve.&lt;/p&gt;

&lt;p&gt;The reference README recommends funding each buyer with the intended buy amount plus an additional ETH buffer for gas.&lt;/p&gt;

&lt;p&gt;The conceptual calculation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wallet balance
      │
      ├── trading capital
      │
      └── gas reserve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not assume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;buyAmount&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;walletBalance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spendable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;gasReserve&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spendable&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Insufficient balance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gas reserve should be configurable rather than buried inside business logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Nonces
&lt;/h2&gt;

&lt;p&gt;Nonce management is another important part of transaction infrastructure.&lt;/p&gt;

&lt;p&gt;For a single wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nonce 10 → transaction A
nonce 11 → transaction B
nonce 12 → transaction C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application must avoid accidental reuse.&lt;/p&gt;

&lt;p&gt;A transaction manager should therefore own nonce allocation rather than having several unrelated services query and assign nonces independently.&lt;/p&gt;

&lt;p&gt;For independent buyer wallets, each wallet naturally has its own nonce sequence.&lt;/p&gt;

&lt;p&gt;That makes the system easier to coordinate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reconciliation
&lt;/h2&gt;

&lt;p&gt;One of the most important features to add after the first working version is reconciliation.&lt;/p&gt;

&lt;p&gt;Suppose the local database says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wallet B
Status: CONFIRMED
Tokens: 10,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not automatically trust the local state.&lt;/p&gt;

&lt;p&gt;Read the chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wallet balance
token balance
transaction receipt
contract state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Local State
     ↕
Chain State
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A reconciliation process can run periodically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;reconcile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WalletState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nativeBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nativeBalance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;tokenBalance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This protects against process crashes, missed RPC responses, reconnects, and inconsistent local state.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recovery
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Master     → CONFIRMED
Wallet A   → CONFIRMED
Wallet B   → CONFIRMED
Wallet C   → REVERTED
Wallet D   → UNKNOWN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A robust system should not restart the entire launch.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Master   → keep
A        → keep
B        → keep
C        → handle failure
D        → reconcile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This requires persistence.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LaunchExecution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;launchId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;masterTx&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;wallets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TxStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the process can restart without losing its understanding of the operation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Idempotency
&lt;/h2&gt;

&lt;p&gt;One particularly dangerous situation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction submitted
        ↓
application crashes
        ↓
restart
        ↓
transaction appears unknown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the application simply submits again, it can unintentionally duplicate an operation.&lt;/p&gt;

&lt;p&gt;Instead, use an execution identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch ID
   │
   ├── Master transaction
   ├── Wallet A transaction
   ├── Wallet B transaction
   └── Wallet C transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On restart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Does this wallet already have
an execution associated with this launch?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If yes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;reconcile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than immediately submitting another transaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Buy, Sell, and Sweep
&lt;/h2&gt;

&lt;p&gt;A Pons automation system should also treat post-launch operations as first-class workflows.&lt;/p&gt;

&lt;p&gt;The reference CLI exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run pons &lt;span class="nt"&gt;--&lt;/span&gt; buy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--token&lt;/span&gt; 0x... &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--file&lt;/span&gt; wallets.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--each-buy&lt;/span&gt; 0.02
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run pons &lt;span class="nt"&gt;--&lt;/span&gt; sell &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--token&lt;/span&gt; 0x... &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--file&lt;/span&gt; wallets.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--percent&lt;/span&gt; 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as well as a wallet sweep operation.&lt;/p&gt;

&lt;p&gt;That naturally leads to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch
  ↓
Entry
  ↓
Position Tracking
  ↓
Exit
  ↓
Fund Management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once these operations share the same execution engine, the system becomes much easier to extend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monitoring
&lt;/h2&gt;

&lt;p&gt;A production application should expose more than transaction hashes.&lt;/p&gt;

&lt;p&gt;Useful metrics include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch status
Transaction status
Wallet balances
Token balances
Quote
Minimum output
Gas usage
Execution latency
Failed transactions
RPC failures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple terminal view could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pons Launch
────────────────────────────

Master
  CONFIRMED
  0x123...

Wallet A
  CONFIRMED
  0x456...

Wallet B
  PENDING
  0x789...

Wallet C
  REVERTED
  0xabc...

Wallet D
  CONFIRMED
  0xdef...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same state can later power a web dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  From CLI to Pons Trading Infrastructure
&lt;/h2&gt;

&lt;p&gt;This is where the project gets more interesting.&lt;/p&gt;

&lt;p&gt;A CLI is only the execution layer.&lt;/p&gt;

&lt;p&gt;The same engine can become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Pons Automation Platform
                           │
        ┌──────────────────┼──────────────────┐
        │                  │                  │
      Launch             Wallets          Positions
        │                  │                  │
        ▼                  ▼                  ▼
   Automation          Management        Tracking
        │                  │                  │
        └──────────────────┼──────────────────┘
                           ▼
                     Execution Engine
                           │
                           ▼
                    Robinhood Chain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then additional services can be added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch Monitor
Copy Trading
Trading Terminal
Analytics
Alerts
Risk Management
Portfolio Tracking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important architecture decision is to keep these strategies above the execution engine.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
   ↓
Risk
   ↓
Execution
   ↓
Blockchain
   ↓
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A strategy should decide &lt;strong&gt;what&lt;/strong&gt; to trade.&lt;/p&gt;

&lt;p&gt;The execution engine should decide &lt;strong&gt;how&lt;/strong&gt; to execute it safely and track what actually happened.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security and Responsible Automation
&lt;/h2&gt;

&lt;p&gt;Multi-wallet launch automation should be used for authorized and legitimate activity.&lt;/p&gt;

&lt;p&gt;The goal of the engineering should be reliable transaction coordination, controlled execution, and accurate state tracking—not artificial volume, wash trading, or market manipulation.&lt;/p&gt;

&lt;p&gt;Private-key management should also be treated as a production security boundary.&lt;/p&gt;

&lt;p&gt;The protocol itself should remain the source of truth for what transactions are permitted, and the application should continuously validate live protocol state.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Would Improve for Production
&lt;/h2&gt;

&lt;p&gt;The reference project is a good example of a focused TypeScript CLI. For a production system, I would build additional layers around it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 ┌─────────────────────┐
                 │   Web Dashboard     │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │   Strategy Layer    │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │   Risk Engine       │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │ Execution Engine    │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │  Pons Protocol      │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │ Robinhood Chain     │
                 └─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI then becomes one interface to the same backend.&lt;/p&gt;




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

&lt;p&gt;A Pons bundler may look like a small blockchain script from the outside.&lt;/p&gt;

&lt;p&gt;The real engineering problem is much larger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Protocol State
      ↓
Launch Validation
      ↓
Wallet Coordination
      ↓
Curve Quoting
      ↓
Slippage Protection
      ↓
Transaction Signing
      ↓
Parallel Execution
      ↓
Receipt Tracking
      ↓
Reconciliation
      ↓
Recovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why I see &lt;strong&gt;Pons bundler&lt;/strong&gt; as more than a single bot.&lt;/p&gt;

&lt;p&gt;It can be the execution foundation for a broader Robinhood Chain trading stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pons Bundler
     ↓
Pons Sniper
     ↓
Pons Copy Trading
     ↓
Pons Trading Terminal
     ↓
Robinhood Chain Trading Infrastructure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting part is not simply interacting with a smart contract.&lt;/p&gt;

&lt;p&gt;It is building an execution system that remains understandable and recoverable when transactions behave differently from what your local application expected.&lt;/p&gt;

&lt;p&gt;That is the difference between a blockchain script and trading infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reference Implementation
&lt;/h2&gt;

&lt;p&gt;The implementation discussed in this article:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/wooyang/pons-bundler" rel="noopener noreferrer"&gt;https://github.com/wooyang/pons-bundler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository documents a TypeScript Pons v2 CLI, launch-and-buy execution, buyer-wallet coordination, curve quoting, dry runs, buying, selling, and wallet management.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>blockchain</category>
      <category>tradingbot</category>
      <category>robinhood</category>
    </item>
    <item>
      <title>Building a Robinhood Chain Trading Bot with TypeScript</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Mon, 07 Sep 2026 15:04:54 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-robinhood-chain-trading-bot-with-typescript-97p</link>
      <guid>https://dev.to/borntoup/building-a-robinhood-chain-trading-bot-with-typescript-97p</guid>
      <description>&lt;p&gt;&lt;em&gt;How to build a modular trading engine for launch detection, token screening, strategy signals, risk controls, execution, and reconciliation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Robinhood Chain is developing a new type of trading environment.&lt;/p&gt;

&lt;p&gt;There are Stock Tokens, DEXs, launchpads, and a growing number of newly created tokens.&lt;/p&gt;

&lt;p&gt;Pons currently lists more than &lt;strong&gt;167,000 launched tokens&lt;/strong&gt; and thousands of tokens that have graduated from its launch process.&lt;/p&gt;

&lt;p&gt;That creates an obvious engineering opportunity:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Automate the process of finding, evaluating, and trading opportunities on Robinhood Chain.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But I would not build a bot as one large script.&lt;/p&gt;

&lt;p&gt;Instead, I'd build a reusable trading engine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Blockchain Events
       ↓
Token Detection
       ↓
Token Screening
       ↓
Strategy
       ↓
Risk Engine
       ↓
Execution
       ↓
Position Management
       ↓
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy can change.&lt;/p&gt;

&lt;p&gt;The underlying engine stays the same.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Build an Engine Instead of a Script?
&lt;/h2&gt;

&lt;p&gt;A simple trading script might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;buy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is easy to write.&lt;/p&gt;

&lt;p&gt;It is also difficult to operate safely.&lt;/p&gt;

&lt;p&gt;A real trading system needs to answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What token was detected?

Why did the strategy select it?

What risk checks passed?

How much capital can be used?

Was the transaction submitted?

Did it succeed?

What position was created?

Does local state match onchain state?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those questions require architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;For an EVM-compatible Robinhood Chain application, a practical stack is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeScript
Node.js
viem
Solidity
Foundry
PostgreSQL
Redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Robinhood's documentation describes Robinhood Chain as EVM-compatible and supports familiar Ethereum tooling.&lt;/p&gt;

&lt;p&gt;A simple project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;robinhood-trading-bot/

src/
  chain/
  market/
  strategies/
  risk/
  execution/
  portfolio/
  reconciliation/
  monitoring/

tests/

contracts/

config/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is separation.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Connect to Robinhood Chain
&lt;/h2&gt;

&lt;p&gt;Start with a public client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RPC_URL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production, the RPC URL should come from configuration rather than being hard-coded.&lt;/p&gt;

&lt;p&gt;You also want the application to validate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Chain ID
RPC connectivity
Latest block
Network configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For mainnet, Robinhood Chain uses chain ID &lt;code&gt;4663&lt;/code&gt;; its testnet uses &lt;code&gt;46630&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Detect New Opportunities
&lt;/h2&gt;

&lt;p&gt;The first module is the detector.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC
 ↓
Blockchain Events
 ↓
Event Decoder
 ↓
Token Candidate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A normalized event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LaunchEvent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;creator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;blockNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transactionHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The detector shouldn't make trading decisions.&lt;/p&gt;

&lt;p&gt;It only answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Something happened.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That makes it reusable for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New launches
Pool creation
Graduations
Large trades
Liquidity changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Token Screening
&lt;/h2&gt;

&lt;p&gt;Next comes token intelligence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch Event
      ↓
Token Screening
      ↓
Candidate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A screening result might contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TokenScreen&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;liquidity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;creator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;holderCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tradingEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Contract exists
Trading enabled
Liquidity available
Expected token configuration
Unexpected permissions
Concentration
Strategy-specific requirements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The purpose isn't to claim a token is “safe.”&lt;/p&gt;

&lt;p&gt;It is to eliminate candidates that fail your predefined requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Strategy Interface
&lt;/h2&gt;

&lt;p&gt;This is where the architecture becomes powerful.&lt;/p&gt;

&lt;p&gt;Instead of hard-coding one strategy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;buy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;define a strategy interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;StrategyContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;liquidity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;blockNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TradeIntent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Strategy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StrategyContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TradeIntent&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now several strategies can use the same engine.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Launch Strategy
&lt;/h2&gt;

&lt;p&gt;A simple launch strategy might require:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Liquidity &amp;gt; minimum
AND
token passes screening
AND
strategy conditions pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LaunchStrategy&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Strategy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StrategyContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TradeIntent&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;liquidity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;MIN_LIQUIDITY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ENTRY_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Launch criteria satisfied&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that this produces a &lt;strong&gt;trade intent&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It does not execute anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Momentum Strategy
&lt;/h2&gt;

&lt;p&gt;The same engine can support momentum.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Price acceleration
+
Volume
+
Liquidity
+
Recent activity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A momentum strategy could expose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MomentumStrategy&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Strategy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StrategyContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TradeIntent&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;momentumCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MOMENTUM_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Momentum threshold reached&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LaunchStrategy
MomentumStrategy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Risk
Execution
Portfolio
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Copy Trading as Another Signal Source
&lt;/h2&gt;

&lt;p&gt;Copy trading can also become a strategy module.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch Event
 ↓
Strategy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tracked Wallet
 ↓
Detected Trade
 ↓
Copy Signal
 ↓
Risk
 ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;WalletTrade&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then normalize it into the same &lt;code&gt;TradeIntent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the advantage of a common strategy interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Risk Engine
&lt;/h2&gt;

&lt;p&gt;Every strategy must go through risk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
   ↓
Risk
   ↓
Approved / Rejected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RiskContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;orderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;currentExposure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxOrderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxExposure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateRisk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RiskContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxOrderValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maximum order exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentExposure&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxExposure&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maximum exposure exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also enforce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum position
Maximum portfolio exposure
Maximum daily loss
Maximum slippage
Maximum number of active positions
Maximum gas cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy generates the idea.&lt;/p&gt;

&lt;p&gt;The risk engine controls the capital.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Global Risk
&lt;/h2&gt;

&lt;p&gt;This becomes important when several strategies run at once.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sniper     → 0.2 ETH
Momentum   → 0.3 ETH
Copy       → 0.4 ETH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each trade might independently pass.&lt;/p&gt;

&lt;p&gt;But the portfolio could still exceed the maximum exposure.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy Risk
      ↓
Portfolio Risk
      ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The risk system should operate at both levels.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Execution Engine
&lt;/h2&gt;

&lt;p&gt;After risk approves the trade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trade Intent
     ↓
Execution Planner
     ↓
Quote
     ↓
Slippage Check
     ↓
Transaction
     ↓
Robinhood Chain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep this logic separate from the strategy.&lt;/p&gt;

&lt;p&gt;A simple interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Executor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TradeIntent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ExecutionResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ExecutionResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;executionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SUCCESS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;executedAmount&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  11. Transaction Simulation
&lt;/h2&gt;

&lt;p&gt;Before sending capital, validate the transaction whenever the execution path supports simulation.&lt;/p&gt;

&lt;p&gt;Check things such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Transaction succeeds
Expected output
Minimum output
Balance
Allowance
Gas estimate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The objective is to catch predictable errors before broadcasting.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Slippage Controls
&lt;/h2&gt;

&lt;p&gt;A strategy shouldn't blindly accept whatever execution price appears.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ExecutionPolicy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;maxSlippageBps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxGas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slippageBps&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxSlippageBps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Slippage exceeds policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is particularly important in low-liquidity markets.&lt;/p&gt;

&lt;p&gt;A strategy can be profitable at one price and unprofitable after execution costs.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Order State
&lt;/h2&gt;

&lt;p&gt;Don't store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and call it finished.&lt;/p&gt;

&lt;p&gt;Use a state machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED
   ↓
RISK_CHECKED
   ↓
SUBMITTED
   ↓
PENDING
   ↓
CONFIRMED
   ↓
SETTLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Failure paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING
 ├──→ FAILED
 └──→ CANCELLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Potential partial execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING
   ↓
PARTIALLY_FILLED
   ↓
SETTLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes recovery much easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Idempotency
&lt;/h2&gt;

&lt;p&gt;Now consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Submit transaction
       ↓
RPC timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The timeout doesn't automatically tell you whether the transaction exists.&lt;/p&gt;

&lt;p&gt;Never treat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as automatically equivalent to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trade failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a unique execution ID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;executionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store it before attempting execution.&lt;/p&gt;

&lt;p&gt;Then the worker can recover after:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Timeout
Crash
Restart
Network failure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;without treating the retry as a new logical trade.&lt;/p&gt;




&lt;h2&gt;
  
  
  15. Position Management
&lt;/h2&gt;

&lt;p&gt;After execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Execution
   ↓
Position
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A position model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Position&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;averageEntryPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;realizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;unrealizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the exit strategy can work against actual portfolio state.&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Exit Automation
&lt;/h2&gt;

&lt;p&gt;Entry is only one half of a trading system.&lt;/p&gt;

&lt;p&gt;A strategy can define:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Take Profit
Stop Loss
Trailing Stop
Time Exit
Partial Exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entry
 ↓
+25% → partial exit
 ↓
+50% → another partial exit
 ↓
Trailing stop → close remainder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These should be deterministic rules in the execution system.&lt;/p&gt;




&lt;h2&gt;
  
  
  17. Reconciliation
&lt;/h2&gt;

&lt;p&gt;This is where many trading bots become unreliable.&lt;/p&gt;

&lt;p&gt;Your application can miss an event.&lt;/p&gt;

&lt;p&gt;A worker can crash.&lt;/p&gt;

&lt;p&gt;An RPC request can time out.&lt;/p&gt;

&lt;p&gt;A database can become temporarily unavailable.&lt;/p&gt;

&lt;p&gt;So periodically compare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Onchain State
      ↕
Internal State
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read token balances
        ↓
Read relevant transactions
        ↓
Check positions
        ↓
Compare
        ↓
Repair
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             ROBINHOOD CHAIN
               /          \
              /            \
          Events             RPC
             ↓                ↓
        Event Worker    Reconciliation
              \              /
               \            /
                 State DB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is one of the most important pieces of reliable blockchain trading infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  18. Monitoring
&lt;/h2&gt;

&lt;p&gt;The bot should expose metrics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;launches_detected
tokens_screened
signals_generated

orders_submitted
orders_confirmed
orders_failed

risk_rejections

execution_latency
gas_used
slippage

position_exposure
reconciliation_errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And useful alerts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC unavailable
Execution failures increasing
Unexpected exposure
Position mismatch
Repeated risk rejection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bot should not be a black box.&lt;/p&gt;




&lt;h2&gt;
  
  
  19. Dashboard
&lt;/h2&gt;

&lt;p&gt;The client needs to see what is happening.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────────┐
│ Robinhood Chain Trading Engine    │
├───────────────────────────────────┤
│                                   │
│ Strategies                        │
│                                   │
│ Launch      RUNNING               │
│ Momentum    RUNNING               │
│ Copy        PAUSED                │
│ Arbitrage   RUNNING               │
│                                   │
│ Portfolio                         │
│ Exposure                          │
│ PnL                               │
│                                   │
│ Recent Signals                    │
│ Recent Executions                 │
│ Risk Events                       │
│                                   │
└───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dashboard is the interface.&lt;/p&gt;

&lt;p&gt;The trading engine is the product.&lt;/p&gt;




&lt;h2&gt;
  
  
  20. Stock Token Arbitrage
&lt;/h2&gt;

&lt;p&gt;The same engine can support Stock Token strategies.&lt;/p&gt;

&lt;p&gt;Robinhood describes Stock Tokens as ERC-20 assets on Robinhood Chain with Chainlink price feeds and documents trading and other composable applications around them. (&lt;a href="https://docs.robinhood.com/chain/stock-tokens" rel="noopener noreferrer"&gt;docs.robinhood.com&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;An arbitrage strategy can compare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stock Token price
       ↓
Oracle/reference price
       ↓
DEX price
       ↓
Spread
       ↓
Gas + slippage
       ↓
Risk
       ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy changes.&lt;/p&gt;

&lt;p&gt;The infrastructure doesn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  21. One Engine, Multiple Strategies
&lt;/h2&gt;

&lt;p&gt;This is the architecture I would ultimately aim for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    TRADING ENGINE
                          │
          ┌───────────────┼───────────────┐
          ↓               ↓               ↓
       LAUNCH          MOMENTUM          COPY
          │               │               │
          └───────────────┼───────────────┘
                          ↓
                 STOCK TOKEN ARB
                          ↓
                         RISK
                          ↓
                      EXECUTION
                          ↓
                      PORTFOLIO
                          ↓
                   RECONCILIATION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy is replaceable.&lt;/p&gt;

&lt;p&gt;The financial infrastructure is reusable.&lt;/p&gt;




&lt;h2&gt;
  
  
  22. Why This Is More Valuable Than a Sniper Script
&lt;/h2&gt;

&lt;p&gt;A simple sniper script answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can I automatically send a buy?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A real trading system answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Can I automatically detect, evaluate, size, execute, manage, and reconcile a trading opportunity?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are very different problems.&lt;/p&gt;

&lt;p&gt;The second one requires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
Strategy
Risk
Execution
State
Reconciliation
Monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the engineering layer clients pay for.&lt;/p&gt;




&lt;h2&gt;
  
  
  23. Building the MVP
&lt;/h2&gt;

&lt;p&gt;I would build the first version in this order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Robinhood Chain connection
2. Event detector
3. Token screening
4. One strategy
5. Risk engine
6. Execution layer
7. Position management
8. Exit rules
9. Reconciliation
10. Monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11. Copy trading
12. Momentum
13. Stock Token arbitrage
14. Portfolio automation
15. AI-generated signals
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the system modular.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Architecture
&lt;/h2&gt;

&lt;p&gt;The finished platform becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    BLOCKCHAIN
                         │
                         ▼
                    DETECTION
                         │
                         ▼
                    ANALYSIS
                         │
                         ▼
                    STRATEGY
                         │
                         ▼
                       RISK
                         │
                         ▼
                    EXECUTION
                         │
                         ▼
                     POSITION
                         │
                         ▼
                       EXIT
                         │
                         ▼
                 RECONCILIATION
                         │
                         ▼
                    MONITORING
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the strategies can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch Sniper
Momentum
Copy Trading
Stock Token Arbitrage
LP Automation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important distinction is that the &lt;strong&gt;bot is not the architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The bot is the strategy layer sitting on top of the architecture.&lt;/p&gt;

&lt;p&gt;That's the approach I would use for Robinhood Chain development.&lt;/p&gt;

&lt;p&gt;The ecosystem is already showing demand for launch detection and automated trading: commercial tools advertise launch/graduation detection, contract screening, automated exits, copy trading and limit orders, while public projects are implementing Robinhood Chain token monitors and trading bots. (&lt;a href="https://www.ponssniperbot.com." rel="noopener noreferrer"&gt;turn565048search0&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;For a developer trying to attract clients, that means the strongest message isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“I build sniper bots.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“I build automated trading infrastructure on Robinhood Chain, and I can turn a specific strategy—sniping, momentum, copy trading, or Stock Token arbitrage—into a production-oriented system.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>typescript</category>
      <category>trading</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>Building a Risk-Controlled Robinhood Trading Bot with TypeScript</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Sat, 05 Sep 2026 11:17:35 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-risk-controlled-robinhood-trading-bot-with-typescript-17om</link>
      <guid>https://dev.to/borntoup/building-a-risk-controlled-robinhood-trading-bot-with-typescript-17om</guid>
      <description>&lt;p&gt;&lt;em&gt;How to turn a trading strategy into a reliable automated system with market data, risk controls, idempotent orders, execution tracking, and reconciliation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A trading bot is often presented as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
    ↓
Strategy
    ↓
Place Order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is enough for a demo.&lt;/p&gt;

&lt;p&gt;It is not enough for a production trading system.&lt;/p&gt;

&lt;p&gt;Once a bot is connected to a real financial account, the difficult questions begin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens when the API times out?&lt;/li&gt;
&lt;li&gt;How do we prevent duplicate orders?&lt;/li&gt;
&lt;li&gt;How do we know whether an order actually executed?&lt;/li&gt;
&lt;li&gt;How do we enforce position and exposure limits?&lt;/li&gt;
&lt;li&gt;What happens when the process restarts?&lt;/li&gt;
&lt;li&gt;How do we reconcile local state with Robinhood?&lt;/li&gt;
&lt;li&gt;How do we stop a broken strategy from repeatedly trading?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Robinhood currently provides a Crypto Trading API that supports market-data access, account information, and programmatic crypto orders. Its order API requires a &lt;code&gt;client_order_id&lt;/code&gt; for idempotency validation. Robinhood also provides an Agentic Trading/MCP interface for supported automated trading workflows.&lt;/p&gt;

&lt;p&gt;This article focuses on the engineering system around those interfaces.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;A trading bot I would actually deploy looks more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌──────────────────┐
                    │   MARKET DATA    │
                    └────────┬─────────┘
                             ↓
                    ┌──────────────────┐
                    │ STRATEGY ENGINE  │
                    └────────┬─────────┘
                             ↓
                    ┌──────────────────┐
                    │   POLICY LAYER   │
                    └────────┬─────────┘
                             ↓
                    ┌──────────────────┐
                    │    RISK ENGINE   │
                    └────────┬─────────┘
                             ↓
                    ┌──────────────────┐
                    │  ORDER MANAGER   │
                    └────────┬─────────┘
                             ↓
                    ┌──────────────────┐
                    │ EXECUTION LAYER  │
                    └────────┬─────────┘
                             ↓
                       ┌────────────┐
                       │ ROBINHOOD  │
                       └─────┬──────┘
                             ↓
                    ┌──────────────────┐
                    │ POSITION / STATE │
                    └────────┬─────────┘
                             ↓
                    ┌──────────────────┐
                    │ RECONCILIATION   │
                    └──────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important idea is that &lt;strong&gt;strategy and execution are different systems&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Market Data
&lt;/h2&gt;

&lt;p&gt;Start with a normalized market-data service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MarketPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;last&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy should receive a clean internal representation rather than knowing how Robinhood's API works.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MarketDataProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MarketPrice&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robinhood API
      ↓
Market Data Adapter
      ↓
Normalized Market Data
      ↓
Strategy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the strategy independent of the data provider.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Validate Data Before Trading
&lt;/h2&gt;

&lt;p&gt;Never assume the latest price is valid.&lt;/p&gt;

&lt;p&gt;At minimum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isFresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;maxAgeMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;maxAgeMs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isFresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Market data is stale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other validation can include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unexpected symbol
Missing bid/ask
Invalid price
Stale timestamp
Market unavailable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bad signal produced from bad data can still be perfectly valid code.&lt;/p&gt;

&lt;p&gt;The system needs to reject it before execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Strategy Engine
&lt;/h2&gt;

&lt;p&gt;The strategy should generate a &lt;strong&gt;signal&lt;/strong&gt;, not place a trade.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TradingSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TradingSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BTC-USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Momentum threshold reached&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipeline is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
     ↓
Strategy
     ↓
Signal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That allows multiple strategies to use the same infrastructure.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Momentum
Mean Reversion
DCA
Rebalancing
Arbitrage
AI-generated signals
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Policy Layer
&lt;/h2&gt;

&lt;p&gt;Policy is different from risk.&lt;/p&gt;

&lt;p&gt;A policy answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is this type of action allowed?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TradingPolicy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;allowedSymbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;maxOrderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxDailyTrades&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;requireApproval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validatePolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TradingSignal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TradingPolicy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedSymbols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Symbol not allowed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is particularly useful for AI-driven systems.&lt;/p&gt;

&lt;p&gt;The model may generate an interesting idea.&lt;/p&gt;

&lt;p&gt;The policy decides whether the agent is even permitted to attempt it.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Risk Engine
&lt;/h2&gt;

&lt;p&gt;Now we ask a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is the trade safe within the current account state?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suppose the strategy generates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY $10,000 BTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the client's limits are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum order: $2,000
Maximum BTC exposure: $5,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The risk engine rejects it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
   ↓
Risk
   ↓
REJECTED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RiskContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;portfolioValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;currentExposure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;orderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxOrderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxExposure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateRisk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RiskContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxOrderValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maximum order size exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentExposure&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxExposure&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maximum exposure exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Production systems can add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum position
Maximum portfolio exposure
Maximum daily loss
Maximum order count
Maximum slippage
Minimum balance
Maximum price age
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Order State Machine
&lt;/h2&gt;

&lt;p&gt;This is where a simple bot becomes a trading system.&lt;/p&gt;

&lt;p&gt;Don't use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPEN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLOSED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use explicit states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED
   ↓
POLICY_CHECKED
   ↓
RISK_CHECKED
   ↓
SUBMITTED
   ↓
PENDING
   ↓
FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Failure paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING
   ├──→ FILLED
   ├──→ CANCELLED
   ├──→ REJECTED
   └──→ FAILED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And potentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING
   ↓
PARTIALLY_FILLED
   ↓
FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An order request is not the same thing as a completed trade.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. Intent ≠ Execution
&lt;/h2&gt;

&lt;p&gt;A useful mental model is:&lt;/p&gt;

&lt;h3&gt;
  
  
  Intent
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 0.01 BTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Submission
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order submitted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.0098 BTC filled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are three different states.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Intent
  ≠
Submission
  ≠
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This distinction prevents a lot of portfolio-state bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Idempotency
&lt;/h2&gt;

&lt;p&gt;This is one of the biggest failure modes in automated trading.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bot
 ↓
Submit order
 ↓
Network timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot doesn't know whether the order reached Robinhood.&lt;/p&gt;

&lt;p&gt;A naive retry can submit a second trade.&lt;/p&gt;

&lt;p&gt;Robinhood's Crypto Trading API requires &lt;code&gt;client_order_id&lt;/code&gt; and documents it as the user-input identifier used for idempotency validation.&lt;/p&gt;

&lt;p&gt;Generate one logical ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientOrderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store it with the order.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Retry
  ↓
Same client_order_id
  ↓
Same logical order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A retry must not become a second trade.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  9. Execution Layer
&lt;/h2&gt;

&lt;p&gt;Keep Robinhood-specific logic inside an adapter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TradingExecutor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OrderRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OrderResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;getOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;cancelOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then your core engine doesn't need to know whether the executor is using an API, MCP-backed service, or another supported execution path.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order Manager
      ↓
Execution Interface
      ↓
Robinhood Adapter
      ↓
Robinhood
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Robinhood's current Crypto Trading API supports market, limit, stop-loss, and stop-limit order types for supported API-tradable pairs.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Position Management
&lt;/h2&gt;

&lt;p&gt;After execution, update your internal position.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;averageEntryPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;realizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;unrealizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BTC
Quantity: 0.25
Average Entry: $105,000
Current Price: $108,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The position engine can calculate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unrealized PnL
Exposure
Portfolio allocation
Risk contribution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And those values feed back into the next risk decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Reconciliation
&lt;/h2&gt;

&lt;p&gt;Real-time events aren't enough.&lt;/p&gt;

&lt;p&gt;Eventually something will go wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API timeout
Worker crash
Database failure
Network interruption
Missed update
Unexpected order status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I would implement reconciliation as a separate process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Robinhood
             /       \
            /         \
      API State       Events
          │             │
          ▼             ▼
    Reconciliation   Event Worker
          │             │
          └──────┬──────┘
                 ↓
             State Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fast path updates state quickly.&lt;/p&gt;

&lt;p&gt;The reconciliation path verifies the state.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every 30–60 seconds

Fetch balances
Fetch positions
Fetch open orders
Check recent trades
Compare local state
Repair mismatches
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of the most important differences between a prototype and a robust trading system.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Database Model
&lt;/h2&gt;

&lt;p&gt;A simple PostgreSQL model might contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;accounts
strategies
orders
executions
positions
reconciliation_runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;client_order_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The unique &lt;code&gt;client_order_id&lt;/code&gt; gives another layer of duplicate protection.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Worker Architecture
&lt;/h2&gt;

&lt;p&gt;I wouldn't execute the entire trading workflow directly inside an HTTP request.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API
 ↓
Create Job
 ↓
Queue
 ↓
Trading Worker
 ↓
Strategy
 ↓
Risk
 ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it easier to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retry safely&lt;/li&gt;
&lt;li&gt;control concurrency&lt;/li&gt;
&lt;li&gt;isolate failures&lt;/li&gt;
&lt;li&gt;process scheduled strategies&lt;/li&gt;
&lt;li&gt;run reconciliation independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A small MVP can still be a single Node.js application.&lt;/p&gt;

&lt;p&gt;The architecture matters more than prematurely introducing microservices.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Example Trading Cycle
&lt;/h2&gt;

&lt;p&gt;A simple deterministic loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tradingCycle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;marketData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BTC-USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isFresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;validatePolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;validateRisk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;buildRiskContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;orderManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what isn't here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI
Wallet logic
Database queries everywhere
Frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each responsibility belongs to its own layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  15. Adding AI
&lt;/h2&gt;

&lt;p&gt;This is where Robinhood's current Agentic Trading infrastructure becomes interesting.&lt;/p&gt;

&lt;p&gt;Robinhood's Trading MCP allows connected AI agents to access portfolio and account information and place supported trades in a dedicated Agentic account. Robinhood describes use cases including automated trading strategies, portfolio rebalancing, and market analysis.&lt;/p&gt;

&lt;p&gt;I'd put the AI above the deterministic trading engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 AI AGENT
                     ↓
                TRADE INTENT
                     ↓
                   POLICY
                     ↓
                    RISK
                     ↓
                 EXECUTION
                     ↓
                 ROBINHOOD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI
 ↓
Direct Trade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model generates the idea.&lt;/p&gt;

&lt;p&gt;The system enforces the rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Example AI Intent
&lt;/h2&gt;

&lt;p&gt;The AI might produce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BTC-USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"side"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BUY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Portfolio is below target allocation"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then deterministic code validates it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Symbol allowed?
       ↓
Order size allowed?
       ↓
Portfolio exposure allowed?
       ↓
Daily loss limit okay?
       ↓
Price fresh?
       ↓
EXECUTE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This architecture is much easier to reason about than allowing the model to directly control execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  17. Stock Tokens and Robinhood Chain
&lt;/h2&gt;

&lt;p&gt;There is a related opportunity for developers with EVM and DeFi experience.&lt;/p&gt;

&lt;p&gt;Robinhood Chain is an EVM-compatible Layer 2, while Robinhood Stock Tokens are standard ERC-20 assets with Chainlink price feeds. Robinhood documents Stock Token applications around trading, lending, portfolio management, and other onchain use cases.&lt;/p&gt;

&lt;p&gt;The same trading architecture can be adapted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stock Token
     ↓
Oracle
     ↓
Strategy
     ↓
Risk
     ↓
Onchain Execution
     ↓
Position
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target allocation
       ↓
Current Stock Token portfolio
       ↓
Rebalance signal
       ↓
      Risk
       ↓
Onchain trade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the skill isn't limited to one Robinhood product.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;financial automation&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  18. API Trading and Onchain Trading Are Different
&lt;/h2&gt;

&lt;p&gt;This distinction matters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robinhood Trading API
        ↓
Brokerage / crypto automation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robinhood Chain
        ↓
Stock Tokens / DeFi / onchain apps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They shouldn't be presented as the same system.&lt;/p&gt;

&lt;p&gt;Robinhood's Chain documentation is explicit that Stock Tokens are onchain ERC-20 assets, while Robinhood's Agentic Trading operates through a dedicated brokerage account and MCP.&lt;/p&gt;

&lt;p&gt;For a developer, however, the underlying engineering concepts overlap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data
 ↓
Strategy
 ↓
Risk
 ↓
Execution
 ↓
State
 ↓
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the reusable part.&lt;/p&gt;




&lt;h2&gt;
  
  
  19. Observability
&lt;/h2&gt;

&lt;p&gt;A trading system should expose metrics such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;orders_created
orders_submitted
orders_filled
orders_failed

risk_rejections
execution_latency
API_latency

position_mismatches
reconciliation_failures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful alerts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API unavailable

Position mismatch

Unexpected trading frequency

Repeated execution failure

Risk limit repeatedly triggered

Reconciliation failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The question isn't only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Is my bot running?”&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Is my bot behaving correctly?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  20. Security
&lt;/h2&gt;

&lt;p&gt;Never put trading credentials in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend code
Git
Logs
localStorage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a production application, credentials and signing material should be isolated from the application layer and managed using appropriate secrets infrastructure.&lt;/p&gt;

&lt;p&gt;Also separate permissions.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
    ↓
  Read

  Risk
    ↓
Decision

Execution
    ↓
Trade permission
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A component that only needs market data shouldn't automatically have trade privileges.&lt;/p&gt;




&lt;h2&gt;
  
  
  21. Failure Testing
&lt;/h2&gt;

&lt;p&gt;The happy path isn't enough.&lt;/p&gt;

&lt;p&gt;I would explicitly test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API timeout
Duplicate request
Invalid order
Stale price
Insufficient balance
Worker restart
Database failure
Network disconnect
Unexpected order status
Reconciliation mismatch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Submit Order
     ↓
Timeout
     ↓
Restart Worker
     ↓
Recover Existing Order
     ↓
Continue Tracking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is much closer to how a real trading system behaves.&lt;/p&gt;




&lt;h2&gt;
  
  
  22. What a Client Actually Gets
&lt;/h2&gt;

&lt;p&gt;A client shouldn't have to hire a developer merely to “connect Robinhood.”&lt;/p&gt;

&lt;p&gt;The valuable deliverable is a complete system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trading Strategy
       ↓
Market Data
       ↓
Risk Controls
       ↓
Automated Execution
       ↓
Portfolio Tracking
       ↓
Monitoring
       ↓
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can become:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a crypto trading bot&lt;/li&gt;
&lt;li&gt;portfolio automation&lt;/li&gt;
&lt;li&gt;a rebalancing engine&lt;/li&gt;
&lt;li&gt;an AI trading agent&lt;/li&gt;
&lt;li&gt;a trading dashboard&lt;/li&gt;
&lt;li&gt;an execution service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the same engineering principles can extend to applications built around Robinhood Stock Tokens.&lt;/p&gt;




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

&lt;p&gt;A Robinhood trading bot is not simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real system is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
     ↓
 Strategy
     ↓
   Policy
     ↓
   Risk
     ↓
Order Manager
     ↓
Execution
     ↓
Robinhood
     ↓
Position
     ↓
Reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when AI is added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Agent
     ↓
Trade Intent
     ↓
 Policy
     ↓
   Risk
     ↓
Execution
     ↓
Robinhood
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model can generate the decision.&lt;/p&gt;

&lt;p&gt;The deterministic system should control the money.&lt;/p&gt;

&lt;p&gt;That is the difference between a &lt;strong&gt;trading demo&lt;/strong&gt; and a &lt;strong&gt;trading automation platform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For developers building around Robinhood today, I think the more valuable question isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do I integrate with Robinhood?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“How do I turn a client's trading strategy into a reliable automated financial system?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where the interesting engineering work begins.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>trading</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building a Robinhood Trading Bot with TypeScript: Market Data, Risk, Execution, and Reconciliation</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Tue, 01 Sep 2026 16:03:30 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-robinhood-trading-bot-with-typescript-market-data-risk-execution-and-reconciliation-2bpe</link>
      <guid>https://dev.to/borntoup/building-a-robinhood-trading-bot-with-typescript-market-data-risk-execution-and-reconciliation-2bpe</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical architecture for turning a trading strategy into a reliable automated trading system.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Building a trading bot is easy to describe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
    ↓
Strategy
    ↓
 Order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building one that can safely run unattended is a different problem.&lt;/p&gt;

&lt;p&gt;A serious automated trading system has to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;market data&lt;/li&gt;
&lt;li&gt;strategy signals&lt;/li&gt;
&lt;li&gt;risk limits&lt;/li&gt;
&lt;li&gt;order state&lt;/li&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;idempotency&lt;/li&gt;
&lt;li&gt;execution&lt;/li&gt;
&lt;li&gt;position tracking&lt;/li&gt;
&lt;li&gt;reconciliation&lt;/li&gt;
&lt;li&gt;monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Robinhood currently provides a Crypto Trading API for programmatic access to market data, account information, and crypto order placement. Robinhood also provides a Trading MCP for its Agentic Trading product, which introduces another way to automate trading workflows. (&lt;a href="https://docs.robinhood.com" rel="noopener noreferrer"&gt;docs.robinhood.com&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This article focuses on the engineering architecture behind a Robinhood trading bot.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;I would structure the system like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  ┌──────────────────┐
                  │   Market Data    │
                  └────────┬─────────┘
                           ↓
                  ┌──────────────────┐
                  │ Strategy Engine  │
                  └────────┬─────────┘
                           ↓
                  ┌──────────────────┐
                  │   Risk Engine    │
                  └────────┬─────────┘
                           ↓
                  ┌──────────────────┐
                  │  Order Manager   │
                  └────────┬─────────┘
                           ↓
                  ┌──────────────────┐
                  │ Execution Engine │
                  └────────┬─────────┘
                           ↓
                     ┌───────────┐
                     │ Robinhood │
                     └─────┬─────┘
                           ↓
                  ┌──────────────────┐
                  │ Position Manager │
                  └────────┬─────────┘
                           ↓
                  ┌──────────────────┐
                  │ Reconciliation   │
                  └──────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend should consume this system.&lt;/p&gt;

&lt;p&gt;It shouldn't contain the core trading logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Market Data
&lt;/h2&gt;

&lt;p&gt;The first layer is the market-data service.&lt;/p&gt;

&lt;p&gt;A simple model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MarketPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;last&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data service should also track:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source
timestamp
symbol
market
data freshness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A trading strategy shouldn't blindly trust every price it receives.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isFresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;maxAgeMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;maxAgeMs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isFresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Market data is stale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact threshold depends on the strategy.&lt;/p&gt;

&lt;p&gt;The important principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A trading decision should know the age and quality of its data.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Strategy Engine
&lt;/h2&gt;

&lt;p&gt;The strategy should produce a signal.&lt;/p&gt;

&lt;p&gt;It should not submit the order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TradingSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TradingSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BTC-USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Momentum threshold reached&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The architecture remains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
     ↓
Strategy
     ↓
Signal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes strategies replaceable.&lt;/p&gt;

&lt;p&gt;You can later implement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Momentum
Mean Reversion
DCA
Rebalancing
Arbitrage
AI Signals
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;without changing the execution layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Risk Engine
&lt;/h2&gt;

&lt;p&gt;The risk engine is the gate between strategy and execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
   ↓
 Risk
   ↓
Approved / Rejected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RiskContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;portfolioValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;currentExposure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;orderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxOrderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxExposure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateRisk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RiskContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxOrderValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maximum order size exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentExposure&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxExposure&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maximum exposure exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A production risk engine can also enforce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum order size
Maximum position size
Maximum portfolio exposure
Maximum daily loss
Maximum number of open orders
Maximum slippage
Minimum balance
Maximum price age
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy decides what it wants.&lt;/p&gt;

&lt;p&gt;The risk engine decides whether it is allowed.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Order State Machine
&lt;/h2&gt;

&lt;p&gt;This is where many simple trading bots start to break down.&lt;/p&gt;

&lt;p&gt;An order shouldn't be modeled as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPEN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLOSED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, use explicit states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED
   ↓
RISK_CHECKED
   ↓
SUBMITTED
   ↓
PENDING
   ↓
FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With failure paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING
   ├──→ FILLED
   ├──→ CANCELLED
   ├──→ REJECTED
   └──→ FAILED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And potentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING
   ↓
PARTIALLY_FILLED
   ↓
FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters because:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Submitted does not mean filled.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A trading engine must distinguish intent, submission, and actual execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Intent vs Execution vs Result
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 0.01 BTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the strategy's intent.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order submitted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's execution.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.0098 BTC actually executed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the result.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Intent
  ≠
Execution
  ≠
Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This mental model makes the rest of the system much easier to design.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Idempotency
&lt;/h2&gt;

&lt;p&gt;Now consider a network timeout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bot
 ↓
Create Order
 ↓
Request sent
 ↓
Timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did Robinhood receive the request?&lt;/p&gt;

&lt;p&gt;The application may not know.&lt;/p&gt;

&lt;p&gt;If the bot blindly retries, it can accidentally create another order.&lt;/p&gt;

&lt;p&gt;Robinhood's Crypto Trading API documents &lt;code&gt;client_order_id&lt;/code&gt; as the client-provided order identifier and uses it for idempotency validation. (&lt;a href="https://docs.robinhood.com" rel="noopener noreferrer"&gt;docs.robinhood.com&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So create a unique identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientOrderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store it before execution.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Retry
  ↓
Same clientOrderId
  ↓
Same logical order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Retries must be safe.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. Execution Service
&lt;/h2&gt;

&lt;p&gt;The execution service translates an approved order into a Robinhood API operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Risk
  ↓
Order
  ↓
Execution Service
  ↓
Robinhood
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A basic domain model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ExecutionResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;clientOrderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;requestedQuantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;executedQuantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;averagePrice&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FILLED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep this layer isolated.&lt;/p&gt;

&lt;p&gt;The strategy should not know how the Robinhood request is constructed.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Position Management
&lt;/h2&gt;

&lt;p&gt;After execution, the system must update positions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;averageEntryPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;realizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;unrealizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Position
   ↓
Current Price
   ↓
Unrealized PnL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Closed Trades
   ↓
Realized PnL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This data is also useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;portfolio dashboards&lt;/li&gt;
&lt;li&gt;performance reports&lt;/li&gt;
&lt;li&gt;risk calculations&lt;/li&gt;
&lt;li&gt;alerts&lt;/li&gt;
&lt;li&gt;strategy evaluation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Reconciliation
&lt;/h2&gt;

&lt;p&gt;Real-time updates are not enough.&lt;/p&gt;

&lt;p&gt;Systems fail.&lt;/p&gt;

&lt;p&gt;You can have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API timeout
Network failure
Worker crash
Missed update
Duplicate message
Database outage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the bot needs reconciliation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast path
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order Update
     ↓
Update Internal State
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Safety path
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Periodic Reconciliation
     ↓
Read Current Account State
     ↓
  Compare
     ↓
  Repair
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every 30–60 seconds

Check balances
Check positions
Check open orders
Check recent executions
Compare internal state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a useful rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Events provide speed. Reconciliation provides confidence.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  10. Database Design
&lt;/h2&gt;

&lt;p&gt;A basic relational model could contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users
accounts
strategies
orders
executions
positions
reconciliation_runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;client_order_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The unique &lt;code&gt;client_order_id&lt;/code&gt; protects against duplicate logical orders.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Worker Architecture
&lt;/h2&gt;

&lt;p&gt;I wouldn't put everything inside the HTTP request.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API
 ↓
Create Strategy Job
 ↓
Queue
 ↓
Trading Worker
 ↓
Risk
 ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A worker can be responsible for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;strategy evaluation
order submission
order tracking
reconciliation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also makes retries easier to control.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Trading Bot Loop
&lt;/h2&gt;

&lt;p&gt;A simple bot loop might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tradingCycle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;market&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;marketData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BTC-USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isFresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;market&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;orderManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part isn't the loop itself.&lt;/p&gt;

&lt;p&gt;The important part is the boundaries around it.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Why Risk Must Be Independent
&lt;/h2&gt;

&lt;p&gt;Imagine a strategy bug:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY
BUY
BUY
BUY
BUY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without an independent risk layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
    ↓
Execution
    ↓
Large position
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With risk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
    ↓
Risk Engine
    ↓
Maximum exposure reached
    ↓
 REJECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why I consider the risk layer a first-class component rather than an optional feature.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Adding AI
&lt;/h2&gt;

&lt;p&gt;Robinhood's Agentic Trading introduces a new possibility: an AI agent can interact with supported trading functionality through Robinhood's MCP. (&lt;a href="https://robinhood.com/us/en/support/articles/agentic-trading-overview" rel="noopener noreferrer"&gt;robinhood.com&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I would integrate it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Agent
    ↓
Trade Intent
    ↓
 Policy
    ↓
Risk Engine
    ↓
Execution
    ↓
Robinhood
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI
 ↓
Direct Trade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI:
"Buy $10,000 BTC"

Policy:
Maximum automated order = $2,000

Risk:
REJECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI can generate the intent.&lt;/p&gt;

&lt;p&gt;The deterministic system remains responsible for authorization.&lt;/p&gt;




&lt;h2&gt;
  
  
  15. Stock Tokens and Robinhood Chain
&lt;/h2&gt;

&lt;p&gt;There is a related onchain opportunity.&lt;/p&gt;

&lt;p&gt;Robinhood Chain is a separate EVM-compatible Layer 2, and its Stock Tokens are ERC-20 assets with Chainlink price feeds. Robinhood documents trading, lending, and other applications that can be built around Stock Tokens. (&lt;a href="https://docs.robinhood.com/chain/stock-tokens" rel="noopener noreferrer"&gt;docs.robinhood.com&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The architecture could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stock Token
     ↓
Price Oracle
     ↓
 Strategy
     ↓
    Risk
     ↓
Onchain Execution
     ↓
  Position
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, a client could want an automated rebalancing application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target Allocation
       ↓
Current Portfolio
       ↓
  Difference
       ↓
Trade Signal
       ↓
     Risk
       ↓
Onchain Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where automated trading and Stock Token applications overlap.&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Example Technology Stack
&lt;/h2&gt;

&lt;p&gt;A practical stack could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Backend
---------
TypeScript
Node.js
viem
PostgreSQL
Redis

Frontend
---------
Next.js
React
TypeScript

Robinhood
---------
Crypto Trading API
Trading MCP

Onchain
-------
Solidity
Foundry
Robinhood Chain
Chainlink
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Robinhood Chain is EVM-compatible and supports familiar Ethereum tooling. (&lt;a href="https://docs.robinhood.com/chain" rel="noopener noreferrer"&gt;docs.robinhood.com&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  17. Production Checklist
&lt;/h2&gt;

&lt;p&gt;Before calling a trading bot production-ready, I'd want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Market-data validation
✓ Risk limits
✓ Order state machine
✓ Idempotency
✓ Retry handling
✓ Position tracking
✓ Reconciliation
✓ Secure credentials
✓ Monitoring
✓ Alerting
✓ Audit logs
✓ Failure recovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The happy path is the easy part.&lt;/p&gt;

&lt;p&gt;The difficult engineering is what happens when something goes wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Architecture
&lt;/h2&gt;

&lt;p&gt;A practical Robinhood trading system becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    MARKET DATA
                         │
                         ▼
                     STRATEGY
                         │
                         ▼
                       RISK
                         │
                         ▼
                       ORDER
                         │
                         ▼
                     EXECUTION
                         │
                         ▼
                    ROBINHOOD
                         │
                         ▼
                    POSITIONS
                         │
                         ▼
                 RECONCILIATION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with AI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  AI AGENT
                     ↓
                TRADE INTENT
                     ↓
                   POLICY
                     ↓
                    RISK
                     ↓
                EXECUTION
                     ↓
                 ROBINHOOD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Robinhood Chain Stock Token applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                STOCK TOKENS
                     ↓
                  ORACLE
                     ↓
                 STRATEGY
                     ↓
                    RISK
                     ↓
             ONCHAIN EXECUTION
                     ↓
                  POSITION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A trading bot isn't an API call wrapped in a loop.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a stateful financial system.&lt;/p&gt;

&lt;p&gt;The strategy is only one component.&lt;/p&gt;

&lt;p&gt;The real engineering value is in making the entire pipeline—&lt;strong&gt;data → decision → risk → execution → state → reconciliation&lt;/strong&gt;—reliable.&lt;/p&gt;

</description>
      <category>api</category>
      <category>architecture</category>
      <category>backend</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Building a Trading Engine for Robinhood Chain: Orders, Execution, Risk, and Reconciliation</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Mon, 31 Aug 2026 15:30:09 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-trading-engine-for-robinhood-chain-orders-execution-risk-and-reconciliation-12mf</link>
      <guid>https://dev.to/borntoup/building-a-trading-engine-for-robinhood-chain-orders-execution-risk-and-reconciliation-12mf</guid>
      <description>&lt;p&gt;&lt;strong&gt;A practical architecture for building financial applications around Robinhood Stock Tokens&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The interesting part of building a trading platform is not the frontend.&lt;/p&gt;

&lt;p&gt;It is not even the smart contract.&lt;/p&gt;

&lt;p&gt;The difficult part is keeping &lt;strong&gt;market data, orders, executions, balances, positions, and risk state consistent&lt;/strong&gt; while everything is happening asynchronously.&lt;/p&gt;

&lt;p&gt;That becomes even more important when building financial applications around onchain assets.&lt;/p&gt;

&lt;p&gt;Robinhood Chain is an Ethereum-compatible Layer 2 designed for onchain financial infrastructure and real-world assets. Its Stock Tokens are standard ERC-20 tokens, which means developers can interact with them using familiar EVM tooling. Robinhood also provides onchain Chainlink price feeds for Stock Tokens.&lt;/p&gt;

&lt;p&gt;That creates an interesting engineering problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do you build a reliable trading engine around programmable real-world assets?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article focuses on that problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Are Building
&lt;/h2&gt;

&lt;p&gt;Instead of starting with a UI, let's start with the trading engine.&lt;/p&gt;

&lt;p&gt;A simplified architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌─────────────────────┐
                    │     Market Data     │
                    │                     │
                    │ APIs / Oracles / RPC│
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │   Strategy Engine   │
                    │                     │
                    │ Signals / Pricing   │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │     Risk Engine     │
                    │                     │
                    │ Limits / Exposure   │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │    Order Manager    │
                    │                     │
                    │ Create / Track      │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │  Execution Engine   │
                    │                     │
                    │ DEX / Smart Contract│
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │ Position Manager    │
                    │                     │
                    │ Balances / PnL      │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │   Reconciliation    │
                    │                     │
                    │ Chain ↔ Internal DB │
                    └─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend sits on top of this system.&lt;/p&gt;

&lt;p&gt;It should not be responsible for maintaining the source of truth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Trading Engine Matters
&lt;/h2&gt;

&lt;p&gt;A common mistake when building trading applications is treating an order as a simple function call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;placeOrder&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a trading system.&lt;/p&gt;

&lt;p&gt;A production system has to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Was the transaction submitted?&lt;/li&gt;
&lt;li&gt;Was it mined?&lt;/li&gt;
&lt;li&gt;Did it succeed?&lt;/li&gt;
&lt;li&gt;How much was actually filled?&lt;/li&gt;
&lt;li&gt;What price was achieved?&lt;/li&gt;
&lt;li&gt;Did the user's balance change?&lt;/li&gt;
&lt;li&gt;Did the position change?&lt;/li&gt;
&lt;li&gt;Did the transaction revert?&lt;/li&gt;
&lt;li&gt;Did the RPC connection disappear?&lt;/li&gt;
&lt;li&gt;Did we receive an event?&lt;/li&gt;
&lt;li&gt;What happens if the event arrives twice?&lt;/li&gt;
&lt;li&gt;What happens if our database says one thing while the blockchain says another?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The blockchain is the final source of truth for onchain state.&lt;/p&gt;

&lt;p&gt;Your database is a &lt;strong&gt;projection of that state&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That distinction is extremely important.&lt;/p&gt;




&lt;h2&gt;
  
  
  Robinhood Chain Is EVM-Compatible
&lt;/h2&gt;

&lt;p&gt;One of the advantages for existing Ethereum developers is that Robinhood Chain uses familiar EVM tooling.&lt;/p&gt;

&lt;p&gt;Robinhood's documentation states that Solidity and Vyper contracts can be deployed without modification, and standard tools such as Hardhat, Foundry, ethers.js, viem, and Wagmi work with the network.&lt;/p&gt;

&lt;p&gt;The current mainnet chain ID is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4663
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The testnet chain ID is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;46630
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ETH is used as the native gas token.&lt;/p&gt;

&lt;p&gt;That means an existing EVM stack can look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend
   │
   ├── Next.js
   ├── React
   └── Wagmi
        │
        ▼
Backend
   │
   ├── Node.js
   ├── TypeScript
   ├── viem
   └── PostgreSQL
        │
        ▼
Robinhood Chain
   │
   ├── Smart Contracts
   ├── Stock Tokens
   └── Chainlink Price Feeds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is not learning an entirely new programming model.&lt;/p&gt;

&lt;p&gt;It is understanding the financial state that you're building around.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stock Tokens as ERC-20 Assets
&lt;/h2&gt;

&lt;p&gt;Robinhood's documentation describes Stock Tokens as standard ERC-20 tokens with 18 decimals.&lt;/p&gt;

&lt;p&gt;Each token corresponds to an underlying equity or ETF and can be held, transferred, and composed into applications. Robinhood also provides Chainlink price feeds for the assets.&lt;/p&gt;

&lt;p&gt;From an application perspective, that gives us a familiar interface.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface IERC20 {
    function balanceOf(address account)
        external
        view
        returns (uint256);

    function transfer(
        address to,
        uint256 amount
    )
        external
        returns (bool);

    function approve(
        address spender,
        uint256 amount
    )
        external
        returns (bool);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important insight is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You don't need to invent a new asset interface just because the underlying asset represents a traditional financial instrument.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can compose the asset using standard EVM infrastructure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Market Data
&lt;/h2&gt;

&lt;p&gt;A trading engine starts with data.&lt;/p&gt;

&lt;p&gt;There are generally several sources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────┐
│ Offchain Market Data │
└──────────┬───────────┘
           │
           ├─────────────┐
           │             │
           ▼             ▼
      REST APIs       WebSockets
           │             │
           └──────┬──────┘
                  │
                  ▼
           Market Data Bus
                  │
                  ▼
          Strategy Engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Stock Tokens specifically, Robinhood provides read-only REST endpoints for asset metadata and prices. The documentation currently lists &lt;code&gt;/assets&lt;/code&gt; and &lt;code&gt;/prices/{symbol}&lt;/code&gt; endpoints and notes that the APIs are rate-limited and cached.&lt;/p&gt;

&lt;p&gt;There is also an important distinction between offchain and onchain prices.&lt;/p&gt;

&lt;p&gt;The REST price endpoint provides the underlying-equity bid/ask.&lt;/p&gt;

&lt;p&gt;The onchain Chainlink feed provides the multiplier-adjusted value.&lt;/p&gt;

&lt;p&gt;If an application mixes these data sources, it needs to understand the corporate-action multiplier rather than assuming the numbers are directly interchangeable.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of detail that can create subtle trading bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Don't Put Market Data Logic Everywhere
&lt;/h2&gt;

&lt;p&gt;A common architecture mistake is allowing every service to query the market independently.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → Price API
Backend  → Price API
Strategy → Price API
Risk     → Price API
Bot      → Price API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates inconsistent state.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                Market Sources
                     │
                     ▼
             Market Data Service
                     │
             ┌───────┴───────┐
             ▼               ▼
         Strategy          Risk
             │               │
             └───────┬───────┘
                     ▼
                 Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The market-data service becomes responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;normalization&lt;/li&gt;
&lt;li&gt;timestamps&lt;/li&gt;
&lt;li&gt;stale-data detection&lt;/li&gt;
&lt;li&gt;symbol mapping&lt;/li&gt;
&lt;li&gt;price validation&lt;/li&gt;
&lt;li&gt;source selection&lt;/li&gt;
&lt;li&gt;caching&lt;/li&gt;
&lt;li&gt;reconnect logic&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Order State Machine
&lt;/h2&gt;

&lt;p&gt;This is one of the most important parts of a trading engine.&lt;/p&gt;

&lt;p&gt;Never model an order as simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPEN
CLOSED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED
   │
   ▼
RISK_CHECKED
   │
   ▼
SUBMITTED
   │
   ▼
PENDING
   │
   ├───────────────┐
   │               │
   ▼               ▼
FILLED          REJECTED
   │
   ▼
SETTLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For partially executed orders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SUBMITTED
    │
    ▼
PARTIALLY_FILLED
    │
    ├──────► FILLED
    │
    └──────► CANCELLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This distinction matters.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ORDER_SUBMITTED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does &lt;strong&gt;not&lt;/strong&gt; mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POSITION_OPEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A transaction may have been submitted but not confirmed.&lt;/p&gt;

&lt;p&gt;A swap may have executed partially or failed.&lt;/p&gt;

&lt;p&gt;A transaction may revert.&lt;/p&gt;

&lt;p&gt;An RPC provider may return a timeout even though the transaction eventually lands.&lt;/p&gt;

&lt;p&gt;The execution engine has to distinguish these states.&lt;/p&gt;




&lt;h2&gt;
  
  
  Idempotency
&lt;/h2&gt;

&lt;p&gt;Suppose your application sends a transaction.&lt;/p&gt;

&lt;p&gt;The RPC request times out.&lt;/p&gt;

&lt;p&gt;Your backend doesn't know whether the transaction was submitted.&lt;/p&gt;

&lt;p&gt;What happens if you retry?&lt;/p&gt;

&lt;p&gt;You could accidentally execute the trade twice.&lt;/p&gt;

&lt;p&gt;That's why execution needs an idempotency layer.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ExecutionRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before submitting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idempotencyKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create the execution record before submitting the transaction.&lt;/p&gt;

&lt;p&gt;The exact implementation will depend on your database and transaction model, but the principle is universal:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A retry must not accidentally become a second trade.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Risk Engine
&lt;/h2&gt;

&lt;p&gt;The strategy should never be allowed to directly execute a trade.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
   │
   ▼
Risk Engine
   │
   ├── Position limit
   ├── Order limit
   ├── Exposure limit
   ├── Slippage limit
   ├── Price freshness
   ├── Balance check
   └── Daily loss limit
   │
   ▼
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RiskRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxSlippageBps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The risk engine might check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_ORDER_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Order exceeds maximum size&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentExposure&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_EXPOSURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Maximum exposure exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;priceAge&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_PRICE_AGE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Market data is stale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is deliberately separate from the strategy.&lt;/p&gt;

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

&lt;p&gt;Because a strategy can be wrong.&lt;/p&gt;

&lt;p&gt;The risk engine should still protect the account.&lt;/p&gt;




&lt;h2&gt;
  
  
  Execution Is Its Own System
&lt;/h2&gt;

&lt;p&gt;Once an order passes risk checks, execution begins.&lt;/p&gt;

&lt;p&gt;A simple model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order
  │
  ▼
Execution Planner
  │
  ├── Route selection
  ├── Price check
  ├── Slippage
  ├── Gas estimation
  └── Transaction construction
  │
  ▼
Transaction
  │
  ▼
RPC
  │
  ▼
Blockchain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution layer should record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transactionHash
wallet
token
amount
expectedAmount
actualAmount
gasUsed
effectivePrice
blockNumber
status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This data becomes essential later for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PnL&lt;/li&gt;
&lt;li&gt;analytics&lt;/li&gt;
&lt;li&gt;reconciliation&lt;/li&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;li&gt;client reporting&lt;/li&gt;
&lt;li&gt;tax/accounting systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Smart Contracts Should Not Become Your Database
&lt;/h2&gt;

&lt;p&gt;Another common mistake is trying to make smart contracts responsible for every piece of application state.&lt;/p&gt;

&lt;p&gt;Instead, think in layers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Onchain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ownership
Balances
Transfers
Settlement
Protocol state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Offchain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Orders
User preferences
Strategies
Risk limits
Execution history
Analytics
Notifications
UI state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The blockchain provides the authoritative settlement layer.&lt;/p&gt;

&lt;p&gt;The backend provides the application layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Position Management
&lt;/h2&gt;

&lt;p&gt;After execution, the system needs to update positions.&lt;/p&gt;

&lt;p&gt;A simplified position might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;averageEntryPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;realizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;unrealizedPnl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;Where did the position come from?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should not blindly trust your local database.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database Position
       │
       │
       ▼
Reconciliation
       ▲
       │
       │
Blockchain Balance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If they disagree, investigate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reconciliation
&lt;/h2&gt;

&lt;p&gt;This is one of the most overlooked parts of trading infrastructure.&lt;/p&gt;

&lt;p&gt;WebSockets can disconnect.&lt;/p&gt;

&lt;p&gt;RPC requests can fail.&lt;/p&gt;

&lt;p&gt;Events can be delayed.&lt;/p&gt;

&lt;p&gt;Workers can crash.&lt;/p&gt;

&lt;p&gt;Databases can become unavailable.&lt;/p&gt;

&lt;p&gt;Your process can restart.&lt;/p&gt;

&lt;p&gt;Therefore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Real-time events are not enough.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You need periodic reconciliation.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every 30 seconds

       ▼
Fetch wallet balances
       │
       ▼
Fetch relevant token balances
       │
       ▼
Read transaction status
       │
       ▼
Compare with internal database
       │
       ▼
Repair discrepancies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The architecture becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Blockchain
              /         \
             /           \
        Events            RPC
          │                │
          ▼                ▼
     Event Processor   Reconciliation
          │                │
          └───────┬────────┘
                  ▼
             State Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you two independent mechanisms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fast path&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Events update state quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safety path&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reconciliation verifies that state is correct.&lt;/p&gt;

&lt;p&gt;That pattern is useful far beyond Robinhood Chain.&lt;/p&gt;

&lt;p&gt;It applies to almost every blockchain-based financial application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling Blockchain Reorganizations and Finality
&lt;/h2&gt;

&lt;p&gt;An application should also avoid assuming that the first observation of a transaction is the final state.&lt;/p&gt;

&lt;p&gt;Depending on the system, you may distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SEEN
 ↓
INCLUDED
 ↓
CONFIRMED
 ↓
FINALIZED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact semantics depend on the chain and application requirements.&lt;/p&gt;

&lt;p&gt;For high-value financial operations, you should define explicitly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what counts as confirmation&lt;/li&gt;
&lt;li&gt;when a position becomes usable&lt;/li&gt;
&lt;li&gt;when funds become withdrawable&lt;/li&gt;
&lt;li&gt;how failed transactions are handled&lt;/li&gt;
&lt;li&gt;how reorgs are handled&lt;/li&gt;
&lt;li&gt;how events are replayed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is that these rules should be part of the system design.&lt;/p&gt;

&lt;p&gt;Not something added after launch.&lt;/p&gt;




&lt;h2&gt;
  
  
  Event Processing
&lt;/h2&gt;

&lt;p&gt;Suppose a contract emits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event SwapExecuted(
    address indexed trader,
    address indexed token,
    uint256 amountIn,
    uint256 amountOut
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your backend consumes the event.&lt;/p&gt;

&lt;p&gt;But what if it receives the same event twice?&lt;/p&gt;

&lt;p&gt;Your database should still produce one logical execution.&lt;/p&gt;

&lt;p&gt;One approach is to create a unique event identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chainId
+
transactionHash
+
logIndex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;transactionHash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;logIndex&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now duplicate delivery becomes harmless.&lt;/p&gt;

&lt;p&gt;This is a small implementation detail that becomes extremely important at scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  Price Oracles
&lt;/h2&gt;

&lt;p&gt;Stock Tokens on Robinhood Chain use Chainlink price feeds.&lt;/p&gt;

&lt;p&gt;A smart contract can therefore consume an oracle rather than depending on a centralized backend for every price-sensitive operation.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface AggregatorV3Interface {
    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A production contract should validate more than just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;answer &amp;gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stale data&lt;/li&gt;
&lt;li&gt;timestamp&lt;/li&gt;
&lt;li&gt;decimals&lt;/li&gt;
&lt;li&gt;expected feed&lt;/li&gt;
&lt;li&gt;asset mapping&lt;/li&gt;
&lt;li&gt;circuit breakers&lt;/li&gt;
&lt;li&gt;unexpected price movements&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require(answer &amp;gt; 0, "invalid price");

require(
    block.timestamp - updatedAt &amp;lt;= MAX_PRICE_AGE,
    "stale price"
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact limits depend on the application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Corporate Actions Are Not Optional
&lt;/h2&gt;

&lt;p&gt;This is a particularly interesting issue for Stock Tokens.&lt;/p&gt;

&lt;p&gt;Robinhood's documentation explains that corporate actions such as dividends and stock splits are handled using an onchain multiplier. The raw token balance can remain unchanged while the shares-per-token relationship changes through the multiplier.&lt;/p&gt;

&lt;p&gt;That means an application should not assume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 token = permanently 1 share
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, the system needs to understand the asset's current multiplier.&lt;/p&gt;

&lt;p&gt;This is a great example of why financial applications require more domain knowledge than simply knowing Solidity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a Simple Service Architecture
&lt;/h2&gt;

&lt;p&gt;A practical backend could be split into several services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌──────────────────┐
                    │     Frontend     │
                    │ Next.js / React  │
                    └────────┬─────────┘
                             │
                             ▼
                    ┌──────────────────┐
                    │    API Gateway   │
                    └────────┬─────────┘
                             │
          ┌──────────────────┼──────────────────┐
          │                  │                  │
          ▼                  ▼                  ▼
   ┌────────────┐     ┌────────────┐     ┌────────────┐
   │ Market Data│     │ Risk Engine│     │ Portfolio  │
   └─────┬──────┘     └─────┬──────┘     └─────┬──────┘
         │                  │                  │
         └──────────────────┼──────────────────┘
                            ▼
                    ┌──────────────────┐
                    │  Order Manager   │
                    └────────┬─────────┘
                             │
                             ▼
                    ┌──────────────────┐
                    │ Execution Engine │
                    └────────┬─────────┘
                             │
                             ▼
                    ┌──────────────────┐
                    │ Robinhood Chain  │
                    └──────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supporting infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PostgreSQL
Redis
Message Queue
RPC Provider
Monitoring
Logging
Alerting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a smaller MVP, these can start as modules inside one Node.js application.&lt;/p&gt;

&lt;p&gt;You don't need microservices on day one.&lt;/p&gt;

&lt;p&gt;The important thing is keeping the responsibilities separated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example TypeScript Domain Model
&lt;/h2&gt;

&lt;p&gt;A simplified order model could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;OrderStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;CREATED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CREATED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;RISK_CHECKED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RISK_CHECKED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SUBMITTED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SUBMITTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;PENDING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;PARTIALLY_FILLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PARTIALLY_FILLED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;FILLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FILLED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CANCELLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CANCELLED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;REJECTED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REJECTED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;FAILED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;requestedAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;executedAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transactionHash&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then enforce valid transitions.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transitions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;CREATED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RISK_CHECKED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REJECTED&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;RISK_CHECKED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUBMITTED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REJECTED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;SUBMITTED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PENDING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FAILED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;PENDING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PARTIALLY_FILLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FILLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CANCELLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FAILED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;PARTIALLY_FILLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FILLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CANCELLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;FILLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;CANCELLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;REJECTED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;FAILED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your system has explicit state transitions rather than arbitrary status updates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where viem Fits
&lt;/h2&gt;

&lt;p&gt;Because Robinhood Chain is EVM-compatible, libraries such as viem can be used for blockchain interaction.&lt;/p&gt;

&lt;p&gt;A basic client might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createWalletClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure the Robinhood Chain network.&lt;/p&gt;

&lt;p&gt;For production systems, I would separate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Public Client
    ↓
Read blockchain state

Wallet Client
    ↓
Sign transactions

Execution Service
    ↓
Submit + monitor transactions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation makes testing and security easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;A financial application should assume that something will eventually go wrong.&lt;/p&gt;

&lt;p&gt;At minimum:&lt;/p&gt;

&lt;h3&gt;
  
  
  Never expose private keys
&lt;/h3&gt;

&lt;p&gt;Private keys should never be stored in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend
localStorage
source code
Git
logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Robinhood's own deployment documentation also explicitly warns developers not to commit real private keys and recommends environment variables and throwaway deployer keys for testing.&lt;/p&gt;

&lt;p&gt;For production systems, consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HSM
MPC
KMS
Vault
Dedicated signing service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;depending on the custody model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Protect the Execution Layer
&lt;/h2&gt;

&lt;p&gt;The execution service should be isolated from arbitrary user input.&lt;/p&gt;

&lt;p&gt;Don't allow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /execute
{
  "to": "0x...",
  "data": "0x..."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;without strict validation.&lt;/p&gt;

&lt;p&gt;Instead, define allowed operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TradeRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BUY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxSlippageBps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then your execution engine constructs the transaction itself.&lt;/p&gt;

&lt;p&gt;This reduces the attack surface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monitoring
&lt;/h2&gt;

&lt;p&gt;A trading engine without monitoring is incomplete.&lt;/p&gt;

&lt;p&gt;Useful metrics include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;orders_submitted
orders_filled
orders_failed
execution_latency
rpc_latency
transaction_failures
reconciliation_errors
stale_price_events
risk_rejections
gas_usage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And alerts such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠ RPC unavailable

⚠ Price feed stale

⚠ Position mismatch

⚠ Unexpected transaction failure

⚠ Reconciliation failed

⚠ Abnormal execution latency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For financial infrastructure, observability is part of correctness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing Strategy
&lt;/h2&gt;

&lt;p&gt;I would test this system at several levels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unit tests
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Risk calculations
Order transitions
Slippage calculations
Position calculations
PnL
Oracle validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integration tests
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wallet → Contract
Contract → Token
Oracle → Contract
Execution → Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Failure tests
&lt;/h3&gt;

&lt;p&gt;These are especially important.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RPC timeout
Duplicate event
Missing event
Transaction revert
Insufficient balance
Stale price
Partial execution
Worker crash
Database failure
Network disconnect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The question isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Does the happy path work?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What happens when every dependency behaves badly?”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A Production Mental Model
&lt;/h2&gt;

&lt;p&gt;I like to think about a trading engine as three different worlds.&lt;/p&gt;

&lt;h2&gt;
  
  
  World 1 — Intent
&lt;/h2&gt;

&lt;p&gt;What the user wants.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 10 AAPL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  World 2 — Execution
&lt;/h2&gt;

&lt;p&gt;What the system attempted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Transaction submitted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  World 3 — Settlement
&lt;/h2&gt;

&lt;p&gt;What actually happened.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9.97 tokens received
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are not necessarily identical.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Intent
  ≠
Execution
  ≠
Settlement
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A reliable trading platform explicitly models all three.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Most Important Architecture Principle
&lt;/h2&gt;

&lt;p&gt;If I had to reduce the entire system to one rule, it would be this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never confuse an instruction with an outcome.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sendTransaction()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is an instruction.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transactionHash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means the transaction was submitted or identified.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;receipt.status === success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means the transaction executed successfully.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;token.balanceOf(wallet)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;tells you the resulting onchain state.&lt;/p&gt;

&lt;p&gt;These are different events.&lt;/p&gt;

&lt;p&gt;Your architecture should reflect that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Becomes Interesting
&lt;/h2&gt;

&lt;p&gt;Once the core trading engine works, much more sophisticated products become possible.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Automated trading
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
     ↓
Strategy
     ↓
Risk
     ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target Allocation
       ↓
Current Portfolio
       ↓
Difference
       ↓
Trade Plan
       ↓
Risk
       ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lending
&lt;/h3&gt;

&lt;p&gt;Stock Tokens could potentially be composed into lending applications, subject to the protocol's supported assets and design. Robinhood specifically identifies lending markets as one possible use case for Stock Tokens.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stock Token
     ↓
Collateral
     ↓
Lending Protocol
     ↓
Borrowing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Structured products
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stock Token
     +
Derivatives
     +
Smart Contract
     ↓
Structured Product
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AI trading agents
&lt;/h3&gt;

&lt;p&gt;And this is where I think the next generation of trading applications gets particularly interesting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Agent
    ↓
Market Analysis
    ↓
Strategy
    ↓
Risk Engine
    ↓
Execution Engine
    ↓
Robinhood Chain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI should &lt;strong&gt;not&lt;/strong&gt; directly control the wallet.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI
 ↓
Trade Intent
 ↓
Risk Engine
 ↓
Policy Validation
 ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deterministic risk layer remains between the AI and the money.&lt;/p&gt;




&lt;h2&gt;
  
  
  Robinhood Chain Is an EVM Opportunity
&lt;/h2&gt;

&lt;p&gt;For Ethereum developers, one of the interesting things about Robinhood Chain is that the learning curve is not equivalent to learning an entirely new blockchain stack.&lt;/p&gt;

&lt;p&gt;The official documentation describes it as fully EVM-compatible and supports familiar Ethereum tooling.&lt;/p&gt;

&lt;p&gt;That means existing experience with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Solidity
Hardhat
Foundry
ethers.js
viem
Wagmi
React
Next.js
Node.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can be transferred directly into the ecosystem.&lt;/p&gt;

&lt;p&gt;The bigger challenge is not the programming language.&lt;/p&gt;

&lt;p&gt;It's understanding financial infrastructure.&lt;/p&gt;




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

&lt;p&gt;Building a financial application on Robinhood Chain isn't simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Smart Contract
+
Frontend
=
Trading Platform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A serious architecture looks more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  ┌──────────────┐
                  │ Market Data  │
                  └──────┬───────┘
                         │
                         ▼
                  ┌──────────────┐
                  │   Strategy   │
                  └──────┬───────┘
                         │
                         ▼
                  ┌──────────────┐
                  │     Risk     │
                  └──────┬───────┘
                         │
                         ▼
                  ┌──────────────┐
                  │    Orders    │
                  └──────┬───────┘
                         │
                         ▼
                  ┌──────────────┐
                  │  Execution   │
                  └──────┬───────┘
                         │
                         ▼
                  ┌──────────────┐
                  │ Robinhood    │
                  │    Chain     │
                  └──────┬───────┘
                         │
                         ▼
                  ┌──────────────┐
                  │Reconciliation│
                  └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The smart contract is only one component.&lt;/p&gt;

&lt;p&gt;The real engineering challenge is building a system that can maintain a correct view of financial state despite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;delayed data&lt;/li&gt;
&lt;li&gt;failed transactions&lt;/li&gt;
&lt;li&gt;duplicate events&lt;/li&gt;
&lt;li&gt;RPC failures&lt;/li&gt;
&lt;li&gt;stale prices&lt;/li&gt;
&lt;li&gt;partial execution&lt;/li&gt;
&lt;li&gt;application crashes&lt;/li&gt;
&lt;li&gt;unexpected market conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is what separates a demo from trading infrastructure.&lt;/p&gt;

&lt;p&gt;And that is where blockchain engineering, backend engineering, and financial engineering start to overlap.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Build Next
&lt;/h2&gt;

&lt;p&gt;If I were turning this architecture into an actual project, I'd build a small working prototype with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Next.js
      +
TypeScript
      +
viem
      +
Robinhood Chain
      +
Stock Tokens
      +
Chainlink price feeds
      +
PostgreSQL
      +
Redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then implement the system incrementally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Connect wallet
2. Read Stock Token balances
3. Read token prices
4. Build portfolio view
5. Create order model
6. Add risk engine
7. Add execution engine
8. Track transactions
9. Build reconciliation
10. Add monitoring
11. Add automated strategy
12. Add AI agent behind the risk layer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That progression turns a simple blockchain demo into something much closer to real financial infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal isn't to build another dashboard.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal is to build a reliable execution system that can safely power the dashboard.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>defi</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Polymarket Bot Execution: Why Detecting a Signal Isn't Enough</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Fri, 28 Aug 2026 13:08:24 +0000</pubDate>
      <link>https://dev.to/borntoup/polymarket-bot-execution-why-detecting-a-signal-isnt-enough-597d</link>
      <guid>https://dev.to/borntoup/polymarket-bot-execution-why-detecting-a-signal-isnt-enough-597d</guid>
      <description>&lt;p&gt;A trading bot can detect the right signal and still lose the trade.&lt;/p&gt;

&lt;p&gt;That sounds strange at first.&lt;/p&gt;

&lt;p&gt;If the strategy correctly identifies an opportunity, shouldn't the bot simply place an order and profit from it?&lt;/p&gt;

&lt;p&gt;In real Polymarket trading, the difficult part often starts &lt;strong&gt;after the signal is detected&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Between:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;signal → order placement → order matching → fill → position management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;the market can change.&lt;/p&gt;

&lt;p&gt;The best price can disappear. Liquidity can move. Your order can be partially filled. The expected edge can disappear before the execution is complete.&lt;/p&gt;

&lt;p&gt;This is one of the reasons building a production-grade &lt;strong&gt;Polymarket trading bot&lt;/strong&gt; is much more complicated than implementing a trading strategy.&lt;/p&gt;




&lt;h2&gt;
  
  
  The basic mistake: treating execution as an afterthought
&lt;/h2&gt;

&lt;p&gt;A simple trading bot might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Receive market data
       ↓
Calculate signal
       ↓
Signal = BUY
       ↓
Place order
       ↓
Done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;It is also incomplete.&lt;/p&gt;

&lt;p&gt;A more realistic execution flow looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market data
     ↓
Signal generation
     ↓
Validate market state
     ↓
Check liquidity
     ↓
Check spread
     ↓
Check current position
     ↓
Determine execution price
     ↓
Place order
     ↓
Monitor order
     ↓
Handle partial/full fill
     ↓
Reconcile position
     ↓
Update risk state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution engine needs to make decisions of its own.&lt;/p&gt;

&lt;p&gt;The strategy answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Should I trade?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The execution engine answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How should I trade right now?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are different problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. A correct signal does not guarantee a profitable fill
&lt;/h2&gt;

&lt;p&gt;Imagine a bot detects a short-term opportunity.&lt;/p&gt;

&lt;p&gt;At the moment the signal is generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best bid:  $0.47
Best ask:  $0.49
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy calculates that buying around &lt;code&gt;$0.49&lt;/code&gt; makes sense.&lt;/p&gt;

&lt;p&gt;The bot receives the signal and begins placing the order.&lt;/p&gt;

&lt;p&gt;But before the order reaches the market:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best bid:  $0.47
Best ask:  $0.52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The market has moved.&lt;/p&gt;

&lt;p&gt;The original edge may no longer exist.&lt;/p&gt;

&lt;p&gt;If the bot blindly executes anyway, it can turn a good signal into a bad trade.&lt;/p&gt;

&lt;p&gt;That's why &lt;strong&gt;signal quality and execution quality need to be evaluated separately&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The order book is part of the strategy
&lt;/h2&gt;

&lt;p&gt;A trading bot should not only ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is the market giving me a signal?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It should also ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does the order book look like right now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Useful execution information can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best bid&lt;/li&gt;
&lt;li&gt;Best ask&lt;/li&gt;
&lt;li&gt;Spread&lt;/li&gt;
&lt;li&gt;Available liquidity&lt;/li&gt;
&lt;li&gt;Depth near the current price&lt;/li&gt;
&lt;li&gt;Recent order-book changes&lt;/li&gt;
&lt;li&gt;Price movement&lt;/li&gt;
&lt;li&gt;Existing position&lt;/li&gt;
&lt;li&gt;Open orders&lt;/li&gt;
&lt;li&gt;Expected fill price&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a strategy may identify a bullish signal.&lt;/p&gt;

&lt;p&gt;But if the available liquidity near the desired entry price is extremely small, blindly entering the position may produce poor execution.&lt;/p&gt;

&lt;p&gt;The strategy can be correct while the trade is still unattractive.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Limit order vs marketable execution
&lt;/h2&gt;

&lt;p&gt;One of the most important decisions is how aggressively the bot should execute.&lt;/p&gt;

&lt;p&gt;A passive limit order attempts to control the execution price.&lt;/p&gt;

&lt;p&gt;An aggressive order prioritizes getting filled.&lt;/p&gt;

&lt;p&gt;Neither is universally better.&lt;/p&gt;

&lt;p&gt;It depends on the strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Passive execution
&lt;/h3&gt;

&lt;p&gt;The bot places an order at a specific price and waits.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better price control&lt;/li&gt;
&lt;li&gt;Potentially lower execution cost&lt;/li&gt;
&lt;li&gt;Useful when the strategy is not extremely time-sensitive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The order may never fill&lt;/li&gt;
&lt;li&gt;The market may move away&lt;/li&gt;
&lt;li&gt;The opportunity may disappear&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Aggressive execution
&lt;/h3&gt;

&lt;p&gt;The bot attempts to get filled against available liquidity.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Higher probability of immediate execution&lt;/li&gt;
&lt;li&gt;Useful when timing is more important than price improvement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can consume liquidity&lt;/li&gt;
&lt;li&gt;Can increase slippage&lt;/li&gt;
&lt;li&gt;Can result in worse average execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The correct choice depends on the expected edge.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The signal can decay while the order is waiting
&lt;/h2&gt;

&lt;p&gt;This is especially important for short-duration prediction markets.&lt;/p&gt;

&lt;p&gt;Suppose the bot estimates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected entry: 0.48
Expected value: 0.54
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy sees an attractive difference.&lt;/p&gt;

&lt;p&gt;The bot places a limit order at &lt;code&gt;0.48&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But the order doesn't fill.&lt;/p&gt;

&lt;p&gt;A few seconds later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market: 0.51
Estimated value: 0.53
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original opportunity is much smaller.&lt;/p&gt;

&lt;p&gt;Should the bot continue waiting?&lt;/p&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;The execution engine needs rules for &lt;strong&gt;stale orders&lt;/strong&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if order_age &amp;gt; max_age:
    cancel order

if expected_edge &amp;lt; minimum_edge:
    cancel order

if market_state_changed:
    cancel or reprice order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact thresholds depend on the strategy.&lt;/p&gt;

&lt;p&gt;The important concept is that &lt;strong&gt;an order should not live forever simply because the original signal was valid&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Partial fills create another problem
&lt;/h2&gt;

&lt;p&gt;Suppose the bot wants to enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target position: 1,000 contracts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But only part of the order gets filled.&lt;/p&gt;

&lt;p&gt;The result might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Requested: 1,000
Filled:      350
Remaining:   650
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the bot has a position.&lt;/p&gt;

&lt;p&gt;But it doesn't have the position it originally intended to build.&lt;/p&gt;

&lt;p&gt;That changes the execution problem.&lt;/p&gt;

&lt;p&gt;The bot now needs to decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep waiting?&lt;/li&gt;
&lt;li&gt;Cancel the remaining order?&lt;/li&gt;
&lt;li&gt;Reprice?&lt;/li&gt;
&lt;li&gt;Submit another order?&lt;/li&gt;
&lt;li&gt;Reduce the target?&lt;/li&gt;
&lt;li&gt;Exit the partial position?&lt;/li&gt;
&lt;li&gt;Continue according to the strategy?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A production bot needs explicit logic for this.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Position state must be reliable
&lt;/h2&gt;

&lt;p&gt;Another common mistake is assuming:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I submitted the order, therefore I have the position.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That isn't necessarily true.&lt;/p&gt;

&lt;p&gt;The bot needs to distinguish between states such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SIGNAL_DETECTED
       ↓
ORDER_SUBMITTED
       ↓
ORDER_OPEN
       ↓
PARTIALLY_FILLED
       ↓
FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it should also handle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ORDER_CANCELLED
ORDER_REJECTED
ORDER_EXPIRED
UNKNOWN_STATE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy should make decisions based on &lt;strong&gt;actual position state&lt;/strong&gt;, not assumptions.&lt;/p&gt;

&lt;p&gt;This becomes especially important when a bot is running continuously.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. WebSocket data is not the same thing as execution state
&lt;/h2&gt;

&lt;p&gt;Real-time market data is extremely useful for a trading bot.&lt;/p&gt;

&lt;p&gt;But market data and account/order state are two different streams of information.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market WebSocket
       ↓
Order book / market state
       ↓
Strategy
       ↓
Execution engine
       ↓
Order management
       ↓
Position/account state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot needs to keep these states synchronized.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market says:
"Opportunity detected"

But execution state says:
"Existing position already open"

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

&lt;/div&gt;



&lt;p&gt;The bot should not blindly submit another order.&lt;/p&gt;

&lt;p&gt;This is why production trading systems need state management rather than just a signal function.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Execution latency matters
&lt;/h2&gt;

&lt;p&gt;Consider a very short-duration strategy.&lt;/p&gt;

&lt;p&gt;The process might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market update
    ↓
Data processing
    ↓
Signal calculation
    ↓
Risk checks
    ↓
Order construction
    ↓
Network request
    ↓
Matching
    ↓
Fill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every step introduces some amount of delay.&lt;/p&gt;

&lt;p&gt;The exact latency isn't the only problem.&lt;/p&gt;

&lt;p&gt;What matters is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What can change during that time?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A strategy that works with a 10-second execution window might behave completely differently if the opportunity disappears within one second.&lt;/p&gt;

&lt;p&gt;This is why backtests that assume instantaneous execution can be misleading.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Backtesting needs an execution model
&lt;/h2&gt;

&lt;p&gt;A common backtesting mistake looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal detected at 0.48

Backtest:
BUY at 0.48
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real execution may look more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal detected at 0.48
       ↓
Available liquidity checked
       ↓
Order submitted
       ↓
First fill: 0.49
       ↓
Second fill: 0.50
       ↓
Remaining order cancelled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backtest and the real bot are now trading completely different conditions.&lt;/p&gt;

&lt;p&gt;A more realistic simulation should consider factors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spread&lt;/li&gt;
&lt;li&gt;Available liquidity&lt;/li&gt;
&lt;li&gt;Execution price&lt;/li&gt;
&lt;li&gt;Slippage&lt;/li&gt;
&lt;li&gt;Partial fills&lt;/li&gt;
&lt;li&gt;Order lifetime&lt;/li&gt;
&lt;li&gt;Position limits&lt;/li&gt;
&lt;li&gt;Fees&lt;/li&gt;
&lt;li&gt;Cancellation&lt;/li&gt;
&lt;li&gt;Market movement after signal generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The closer the execution model is to reality, the more useful the backtest becomes.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Execution should have its own risk controls
&lt;/h2&gt;

&lt;p&gt;A trading strategy can have risk management.&lt;/p&gt;

&lt;p&gt;The execution engine should have risk management too.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum order size
Maximum position
Maximum exposure
Maximum slippage
Maximum order lifetime
Maximum number of open orders
Maximum daily loss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before submitting an order, the bot can validate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is the market still valid?

Is the price still acceptable?

Is enough liquidity available?

Is the position within limits?

Is the expected edge still large enough?

Is another order already active?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the answer is no, the correct action may be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do nothing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not every detected opportunity should become a trade.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. A better Polymarket bot architecture
&lt;/h2&gt;

&lt;p&gt;For a more serious system, I prefer separating the components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  MARKET DATA
                       │
                       ▼
              ┌─────────────────┐
              │  Market State   │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ Signal Engine   │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ Risk Engine     │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ Execution Engine│
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ Order Manager   │
              └────────┬────────┘
                       │
                       ▼
                 POLYMARKET
                       │
                       ▼
              ┌─────────────────┐
              │ Position State  │
              └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;For example, the same execution engine could potentially support different strategies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Momentum Strategy ─────┐
Arbitrage Strategy ────┼──→ Risk Engine → Execution Engine
TWAP Strategy ─────────┤
Market Making ─────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The execution engine determines &lt;strong&gt;how to execute it&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. This is where TWAP becomes interesting
&lt;/h2&gt;

&lt;p&gt;TWAP is often described simply as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Split a large order into smaller orders over time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But implementation is more complicated.&lt;/p&gt;

&lt;p&gt;A useful TWAP system needs to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Target size&lt;/li&gt;
&lt;li&gt;Remaining size&lt;/li&gt;
&lt;li&gt;Time interval&lt;/li&gt;
&lt;li&gt;Current liquidity&lt;/li&gt;
&lt;li&gt;Current price&lt;/li&gt;
&lt;li&gt;Existing fills&lt;/li&gt;
&lt;li&gt;Failed orders&lt;/li&gt;
&lt;li&gt;Partial fills&lt;/li&gt;
&lt;li&gt;Market conditions&lt;/li&gt;
&lt;li&gt;Maximum acceptable execution price&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple schedule might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target: 1,000
Duration: 10 minutes

100 → 100 → 100 → 100 → ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more adaptive system might instead say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;If liquidity is healthy:
    execute normally

If liquidity disappears:
    slow down

If price moves outside tolerance:
    pause

If order partially fills:
    recalculate remaining quantity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That turns TWAP from a timer into an actual execution system.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. The important lesson
&lt;/h2&gt;

&lt;p&gt;Building a Polymarket trading bot is not simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if signal:
    buy()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A real system needs to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is the signal still valid?&lt;/p&gt;

&lt;p&gt;Is the market still liquid?&lt;/p&gt;

&lt;p&gt;What price should I accept?&lt;/p&gt;

&lt;p&gt;How much should I execute?&lt;/p&gt;

&lt;p&gt;What happens if only part of the order fills?&lt;/p&gt;

&lt;p&gt;What happens if the market moves?&lt;/p&gt;

&lt;p&gt;When should I cancel?&lt;/p&gt;

&lt;p&gt;What is my current position?&lt;/p&gt;

&lt;p&gt;Is the trade still worth taking?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These execution decisions can determine whether a strategy that looks good on paper survives in a live market.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. What I focus on when building trading bots
&lt;/h2&gt;

&lt;p&gt;When I build automated trading systems, I don't treat the strategy as the entire product.&lt;/p&gt;

&lt;p&gt;I look at the complete pipeline:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market data → strategy → risk → execution → order management → position management → monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For Polymarket specifically, that can involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLOB market data&lt;/li&gt;
&lt;li&gt;Real-time order-book monitoring&lt;/li&gt;
&lt;li&gt;WebSocket infrastructure&lt;/li&gt;
&lt;li&gt;Automated order execution&lt;/li&gt;
&lt;li&gt;Limit/marketable execution logic&lt;/li&gt;
&lt;li&gt;Partial-fill handling&lt;/li&gt;
&lt;li&gt;Position tracking&lt;/li&gt;
&lt;li&gt;TWAP execution&lt;/li&gt;
&lt;li&gt;Arbitrage logic&lt;/li&gt;
&lt;li&gt;Risk controls&lt;/li&gt;
&lt;li&gt;Monitoring and logging&lt;/li&gt;
&lt;li&gt;Backtesting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal isn't simply to make the bot generate signals.&lt;/p&gt;

&lt;p&gt;The goal is to make the entire system behave correctly when the market does something unexpected.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a custom Polymarket trading bot?
&lt;/h2&gt;

&lt;p&gt;If you already have a strategy and want to automate it, the strategy itself is only the starting point.&lt;/p&gt;

&lt;p&gt;A proper implementation needs to define:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What markets should be monitored?&lt;/li&gt;
&lt;li&gt;What creates an entry signal?&lt;/li&gt;
&lt;li&gt;What invalidates the signal?&lt;/li&gt;
&lt;li&gt;How should orders be executed?&lt;/li&gt;
&lt;li&gt;How much liquidity is required?&lt;/li&gt;
&lt;li&gt;How should partial fills be handled?&lt;/li&gt;
&lt;li&gt;What are the position limits?&lt;/li&gt;
&lt;li&gt;When should orders be cancelled?&lt;/li&gt;
&lt;li&gt;How should the bot recover from failures?&lt;/li&gt;
&lt;li&gt;What should be monitored after deployment?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I build custom &lt;strong&gt;Polymarket trading bots and automated execution systems&lt;/strong&gt; around specific strategies and execution requirements.&lt;/p&gt;

&lt;p&gt;My work focuses on the engineering side: real-time market data, order-book analysis, CLOB execution, TWAP, automated order management, risk controls and monitoring.&lt;/p&gt;

&lt;p&gt;I've also been building a Polymarket TWAP trading bot and making the implementation available on GitHub:&lt;/p&gt;

&lt;p&gt;If you have a Polymarket strategy you want automated, send me the strategy, target markets, expected position size and execution requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The interesting part isn't just finding the trade. It's building the system that can actually execute it.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Polymarket Bot Order-Book Imbalance: How to Detect Real Market Pressure</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Thu, 27 Aug 2026 20:24:42 +0000</pubDate>
      <link>https://dev.to/borntoup/polymarket-bot-order-book-imbalance-how-to-detect-real-market-pressure-3nm0</link>
      <guid>https://dev.to/borntoup/polymarket-bot-order-book-imbalance-how-to-detect-real-market-pressure-3nm0</guid>
      <description>&lt;p&gt;Order-book imbalance looks simple.&lt;/p&gt;

&lt;p&gt;Count the bids.&lt;/p&gt;

&lt;p&gt;Count the asks.&lt;/p&gt;

&lt;p&gt;Compare them.&lt;/p&gt;

&lt;p&gt;If bids are much larger than asks, the market looks bullish.&lt;/p&gt;

&lt;p&gt;If asks are much larger than bids, the market looks bearish.&lt;/p&gt;

&lt;p&gt;But building a Polymarket bot around that assumption can be a serious mistake.&lt;/p&gt;

&lt;p&gt;A large imbalance does not automatically mean the price will move.&lt;/p&gt;

&lt;p&gt;Orders can disappear.&lt;/p&gt;

&lt;p&gt;New liquidity can arrive.&lt;/p&gt;

&lt;p&gt;Trades can consume one side of the book.&lt;/p&gt;

&lt;p&gt;The spread can change.&lt;/p&gt;

&lt;p&gt;And the imbalance that looked strong 200 milliseconds ago may no longer exist.&lt;/p&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How can a Polymarket bot determine whether order-book imbalance represents meaningful market pressure or temporary noise?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where the engineering becomes interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Order-Book Imbalance?
&lt;/h2&gt;

&lt;p&gt;For a simple order book, define:&lt;/p&gt;

&lt;p&gt;Bid Volume = total size on the bid side&lt;/p&gt;

&lt;p&gt;Ask Volume = total size on the ask side&lt;/p&gt;

&lt;p&gt;A basic imbalance formula is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance =
(Bid Volume - Ask Volume)
/
(Bid Volume + Ask Volume)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-1 and +1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bid Volume = 800
Ask Volume = 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(800 - 200) / (800 + 200)

= 600 / 1000

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

&lt;/div&gt;



&lt;p&gt;The result is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+0.60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means the displayed bid-side liquidity is significantly larger than the ask-side liquidity.&lt;/p&gt;

&lt;p&gt;But this is only a snapshot.&lt;/p&gt;

&lt;p&gt;It is not a trading decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Single Imbalance Snapshot Is Dangerous
&lt;/h2&gt;

&lt;p&gt;Imagine your Polymarket bot sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.70
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot buys immediately.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 ms later → +0.35
200 ms later → +0.10
300 ms later → -0.05
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original imbalance disappeared.&lt;/p&gt;

&lt;p&gt;What happened?&lt;/p&gt;

&lt;p&gt;Possibilities include:&lt;/p&gt;

&lt;p&gt;• Large bids were cancelled&lt;/p&gt;

&lt;p&gt;• New asks appeared&lt;/p&gt;

&lt;p&gt;• Trades consumed the bids&lt;/p&gt;

&lt;p&gt;• Price moved&lt;/p&gt;

&lt;p&gt;• Liquidity migrated to another level&lt;/p&gt;

&lt;p&gt;The bot wasn't necessarily wrong about the data.&lt;/p&gt;

&lt;p&gt;The problem was treating a temporary observation as a persistent signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persistence Matters
&lt;/h2&gt;

&lt;p&gt;This is one of the first improvements I would make to a Polymarket bot.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the current imbalance?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How long has the imbalance remained meaningful?&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 → +0.68
t1 → +0.71
t2 → +0.69
t3 → +0.73
t4 → +0.66
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is more interesting than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 → +0.70
t1 → +0.12
t2 → -0.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both examples contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+0.70
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But they describe very different market conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Imbalance Signal
&lt;/h2&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IF imbalance &amp;gt; threshold
    BUY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I prefer thinking in terms of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance
+
Persistence
+
Price Movement
+
Trade Flow
+
Liquidity
+
Spread
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the bot can decide whether the imbalance is strong enough to influence execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Levels Should You Measure?
&lt;/h2&gt;

&lt;p&gt;Another important question is:&lt;/p&gt;

&lt;p&gt;How much of the order book should be included?&lt;/p&gt;

&lt;p&gt;Suppose the book is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bid

0.48 → 100
0.47 → 200
0.46 → 300
0.45 → 800
0.44 → 1500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ask

0.52 → 100
0.53 → 150
0.54 → 200
0.55 → 300
0.56 → 400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you include every level, the distant 0.45 bid can dominate your calculation.&lt;/p&gt;

&lt;p&gt;But that liquidity may have very little relevance to the immediate execution price.&lt;/p&gt;

&lt;p&gt;So the bot needs to define an observation window.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Top 1 level
Top 3 levels
Top 5 levels
Price-distance window
Depth within X ticks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There isn't one universally correct choice.&lt;/p&gt;

&lt;p&gt;It depends on the strategy and market.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top-of-Book Imbalance
&lt;/h2&gt;

&lt;p&gt;The simplest approach is to compare only the best bid and best ask sizes.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best Bid Size = 500
Best Ask Size = 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = (500 - 100) / (500 + 100)

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

&lt;/div&gt;



&lt;p&gt;This is fast.&lt;/p&gt;

&lt;p&gt;But it can also be fragile.&lt;/p&gt;

&lt;p&gt;A single large order can make the imbalance look extreme.&lt;/p&gt;

&lt;p&gt;If that order disappears, the signal disappears with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Level Imbalance
&lt;/h2&gt;

&lt;p&gt;A more stable approach is to use several levels.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bid:

0.50 → 200
0.49 → 150
0.48 → 100

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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ask:

0.51 → 100
0.52 → 100
0.53 → 100

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

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance =
(450 - 300) / (450 + 300)

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

&lt;/div&gt;



&lt;p&gt;This gives a different picture from looking only at the best level.&lt;/p&gt;

&lt;p&gt;The important engineering decision is to make the depth window configurable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weighting Distance From the Mid Price
&lt;/h2&gt;

&lt;p&gt;Not all liquidity should necessarily have equal weight.&lt;/p&gt;

&lt;p&gt;Liquidity close to the current market may matter more than liquidity far away.&lt;/p&gt;

&lt;p&gt;So you can introduce weights.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Weighted Imbalance =
Weighted Bid Depth
-
Weighted Ask Depth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where levels closer to the midpoint receive greater weight.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Level 1 → weight 1.00
Level 2 → weight 0.75
Level 3 → weight 0.50
Level 4 → weight 0.25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact weighting function is something I would test rather than hard-code permanently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imbalance vs Price Movement
&lt;/h2&gt;

&lt;p&gt;This is where the signal becomes much more useful.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.65
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Price = unchanged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is different from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.65
Price = rising
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And different again from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.65
Price = falling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same imbalance can have different meanings depending on what price is doing.&lt;/p&gt;

&lt;p&gt;So a Polymarket bot should not necessarily interpret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.65
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Trade Flow
&lt;/h2&gt;

&lt;p&gt;Displayed liquidity is not the same thing as executed liquidity.&lt;/p&gt;

&lt;p&gt;This is an important distinction.&lt;/p&gt;

&lt;p&gt;The order book tells you what traders are currently displaying.&lt;/p&gt;

&lt;p&gt;Trades tell you what actually happened.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bid imbalance = +0.60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but recent trades are repeatedly hitting the bids.&lt;/p&gt;

&lt;p&gt;That could indicate that the displayed bid liquidity is being consumed.&lt;/p&gt;

&lt;p&gt;Now consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bid imbalance = +0.60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while aggressive buying is repeatedly lifting the asks.&lt;/p&gt;

&lt;p&gt;That is a very different situation.&lt;/p&gt;

&lt;p&gt;So I would track:&lt;/p&gt;

&lt;p&gt;• Order-book imbalance&lt;/p&gt;

&lt;p&gt;• Recent trade direction&lt;/p&gt;

&lt;p&gt;• Trade volume&lt;/p&gt;

&lt;p&gt;• Price movement&lt;/p&gt;

&lt;p&gt;• Liquidity changes&lt;/p&gt;

&lt;h2&gt;
  
  
  Liquidity Appearance vs Liquidity Consumption
&lt;/h2&gt;

&lt;p&gt;This distinction is extremely important.&lt;/p&gt;

&lt;p&gt;Suppose a large bid appears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 1,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot might interpret this as strong support.&lt;/p&gt;

&lt;p&gt;But if the order disappears before any meaningful trading occurs, it may have provided little real support.&lt;/p&gt;

&lt;p&gt;On the other hand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 1,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;appears and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;300 traded
400 traded
200 traded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the displayed liquidity has actually participated in execution.&lt;/p&gt;

&lt;p&gt;This is why I would track both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Displayed Liquidity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumed Liquidity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Imbalance Can Move Before Price
&lt;/h2&gt;

&lt;p&gt;A useful feature for a Polymarket bot is to monitor the sequence of events.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Bid depth increases
2. Imbalance becomes positive
3. Ask depth decreases
4. Trades begin lifting the ask
5. Mid price moves
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sequence can be more informative than simply observing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.70
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order of events matters.&lt;/p&gt;

&lt;p&gt;That means the bot should store short-term market history rather than only the latest book snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use a Rolling Window
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;last 100 ms
last 250 ms
last 500 ms
last 1 second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current Imbalance
Average Imbalance
Maximum Imbalance
Minimum Imbalance
Imbalance Duration
Imbalance Change
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the strategy can distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strong + persistent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strong + temporary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Imbalance Velocity
&lt;/h2&gt;

&lt;p&gt;Another useful feature is how quickly imbalance changes.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 = 0.10
t1 = 0.30
t2 = 0.50
t3 = 0.70
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The imbalance is increasing rapidly.&lt;/p&gt;

&lt;p&gt;Compare that with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 = 0.70
t1 = 0.69
t2 = 0.68
t3 = 0.67
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second case still has positive imbalance.&lt;/p&gt;

&lt;p&gt;But the pressure is weakening.&lt;/p&gt;

&lt;p&gt;So instead of only calculating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imbalance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imbalance_change
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and potentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imbalance_velocity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Don't Let Imbalance Override the Strategy
&lt;/h2&gt;

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

&lt;p&gt;I would not build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IF imbalance &amp;gt; 0.5
    BUY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as the complete strategy.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy Signal
+
Order-Book Imbalance
+
Trade Flow
+
Price Movement
+
Liquidity
+
Risk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;should influence the final decision.&lt;/p&gt;

&lt;p&gt;Imbalance should often be a feature.&lt;/p&gt;

&lt;p&gt;Not the entire strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Two Different Markets
&lt;/h2&gt;

&lt;p&gt;Consider Market A:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.70
Persistence = 50 ms
Price = falling
Trade flow = selling
Spread = widening
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That doesn't look like a strong long setup.&lt;/p&gt;

&lt;p&gt;Now Market B:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance = +0.65
Persistence = 800 ms
Price = rising
Trade flow = buying
Spread = stable
Liquidity = increasing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a much more interesting condition.&lt;/p&gt;

&lt;p&gt;The numerical imbalance is similar.&lt;/p&gt;

&lt;p&gt;The market context is completely different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imbalance and Execution
&lt;/h2&gt;

&lt;p&gt;This is where the feature becomes useful for a Polymarket bot.&lt;/p&gt;

&lt;p&gt;Suppose the strategy already wants to buy.&lt;/p&gt;

&lt;p&gt;The execution engine sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strong positive imbalance
+
Positive trade flow
+
Stable spread
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may decide that waiting for a lower passive price has a higher opportunity cost.&lt;/p&gt;

&lt;p&gt;The bot could therefore become more aggressive.&lt;/p&gt;

&lt;p&gt;Now consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Weakening imbalance
+
Negative trade flow
+
Widening spread
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution engine may reduce size or wait.&lt;/p&gt;

&lt;p&gt;This creates a better relationship between:&lt;/p&gt;

&lt;p&gt;Signal&lt;/p&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;p&gt;Execution Policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imbalance Can Also Tell the Bot When Not to Trade
&lt;/h2&gt;

&lt;p&gt;This is often overlooked.&lt;/p&gt;

&lt;p&gt;A good trading feature doesn't only answer:&lt;/p&gt;

&lt;p&gt;"BUY?"&lt;/p&gt;

&lt;p&gt;It can also answer:&lt;/p&gt;

&lt;p&gt;"WAIT."&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy = BUY

Imbalance = unstable
Spread = widening
Liquidity = falling
Trade flow = conflicting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best decision may be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WAIT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot doesn't need to trade every time the strategy detects a theoretical opportunity.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Imbalance Score
&lt;/h2&gt;

&lt;p&gt;You could create a composite score such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Score =
w1 × Imbalance
+
w2 × Persistence
+
w3 × TradeFlow
+
w4 × PriceMomentum
+
w5 × LiquidityChange
-
w6 × Spread
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The weights should be determined through testing.&lt;/p&gt;

&lt;p&gt;The important part is that the model combines multiple pieces of market information.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Score &amp;gt; Entry Threshold
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;could permit execution.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Score &amp;lt; Entry Threshold
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;could result in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WAIT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Avoid Hard-Coded Thresholds
&lt;/h2&gt;

&lt;p&gt;A common mistake is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imbalance &amp;gt; 0.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;forever.&lt;/p&gt;

&lt;p&gt;Different markets can behave differently.&lt;/p&gt;

&lt;p&gt;Liquidity can vary.&lt;/p&gt;

&lt;p&gt;Time-to-resolution can vary.&lt;/p&gt;

&lt;p&gt;Spread can vary.&lt;/p&gt;

&lt;p&gt;Market participants can vary.&lt;/p&gt;

&lt;p&gt;So thresholds should ideally be configurable and tested against historical data.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imbalanceThreshold
minimumPersistence
maxSpread
minimumDepth
minimumTradeVolume
maxSignalAge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These should be strategy parameters, not hidden constants throughout the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal Freshness Matters
&lt;/h2&gt;

&lt;p&gt;Even a strong imbalance can become stale.&lt;/p&gt;

&lt;p&gt;A simplified execution flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ORDER BOOK UPDATE
        ↓
FEATURE CALCULATION
        ↓
SIGNAL
        ↓
VALIDATION
        ↓
EXECUTION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the bot waits too long between those stages, the market state may have changed.&lt;/p&gt;

&lt;p&gt;So I would associate each signal with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;signalTimestamp
bookTimestamp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and calculate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;signalAge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;signalAge &amp;gt; maximumAllowedAge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the bot should invalidate the signal and recalculate.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Architecture
&lt;/h2&gt;

&lt;p&gt;For a production-style Polymarket bot, I would separate the components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
    ↓
Order Book
    ↓
Feature Engine
    ↓
Imbalance Calculator
    ↓
Signal Engine
    ↓
Risk Engine
    ↓
Execution Engine
    ↓
Order Manager
    ↓
Position Manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The imbalance calculator shouldn't place orders.&lt;/p&gt;

&lt;p&gt;The strategy shouldn't directly manipulate balances.&lt;/p&gt;

&lt;p&gt;The execution engine shouldn't decide the market direction.&lt;/p&gt;

&lt;p&gt;Each component should have a clear responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Log
&lt;/h2&gt;

&lt;p&gt;When the bot trades because of an imbalance-related signal, I want to know exactly why.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SIGNAL

imbalance = 0.64
imbalance_duration = 620ms
trade_flow = +0.72
price_change = +0.004
spread = 0.01
depth = 840
signal_age = 18ms

DECISION

signal = BUY
confidence = HIGH
order_size = 100

EXECUTION

order_type = LIMIT
price = 0.54
filled = 82
remaining = 18
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the strategy testable.&lt;/p&gt;

&lt;p&gt;Without this information, you may only see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY
SELL
P&amp;amp;L
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and have no idea why the bot made its decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backtesting the Feature
&lt;/h2&gt;

&lt;p&gt;Before trusting order-book imbalance with real capital, I would test:&lt;/p&gt;

&lt;p&gt;• Different depth windows&lt;/p&gt;

&lt;p&gt;• Different imbalance thresholds&lt;/p&gt;

&lt;p&gt;• Different persistence requirements&lt;/p&gt;

&lt;p&gt;• Different market conditions&lt;/p&gt;

&lt;p&gt;• Different time-to-resolution ranges&lt;/p&gt;

&lt;p&gt;• Different liquidity levels&lt;/p&gt;

&lt;p&gt;• Different spreads&lt;/p&gt;

&lt;p&gt;• Different execution delays&lt;/p&gt;

&lt;p&gt;The important metric isn't simply:&lt;/p&gt;

&lt;p&gt;"Did price go up after positive imbalance?"&lt;/p&gt;

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

&lt;p&gt;"Could the bot actually execute the trade at the assumed price?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The Difference Between Prediction and Execution
&lt;/h2&gt;

&lt;p&gt;This is the key lesson.&lt;/p&gt;

&lt;p&gt;Suppose positive imbalance predicts that price will move higher.&lt;/p&gt;

&lt;p&gt;That doesn't automatically mean the bot can profit from it.&lt;/p&gt;

&lt;p&gt;The bot still needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prediction
+
Entry Price
+
Execution Probability
+
Slippage
+
Position Size
+
Exit
+
Risk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A feature can be statistically useful and still be economically useless after execution costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rule I Would Use
&lt;/h2&gt;

&lt;p&gt;I wouldn't build a Polymarket bot around:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance → Buy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance
      +
Persistence
      +
Trade Flow
      +
Price
      +
Liquidity
      +
Spread
      +
Strategy
      +
Risk
      ↓
Execution Decision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a much more robust way to think about order-book imbalance.&lt;/p&gt;

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

&lt;p&gt;Order-book imbalance is one of those features that looks extremely simple at first.&lt;/p&gt;

&lt;p&gt;Calculate bid volume.&lt;/p&gt;

&lt;p&gt;Calculate ask volume.&lt;/p&gt;

&lt;p&gt;Compare them.&lt;/p&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;p&gt;But real markets aren't static.&lt;/p&gt;

&lt;p&gt;Liquidity changes.&lt;/p&gt;

&lt;p&gt;Orders disappear.&lt;/p&gt;

&lt;p&gt;Trades consume liquidity.&lt;/p&gt;

&lt;p&gt;Prices move.&lt;/p&gt;

&lt;p&gt;Spreads change.&lt;/p&gt;

&lt;p&gt;Signals become stale.&lt;/p&gt;

&lt;p&gt;That's why the useful question isn't:&lt;/p&gt;

&lt;p&gt;"Is there an imbalance?"&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is the imbalance persistent, meaningful, tradable, and consistent with the rest of the market state?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the difference between adding an indicator to a bot and actually engineering an execution system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;I'm continuing this practical Polymarket bot engineering series.&lt;/p&gt;

&lt;p&gt;The next problem I want to explore is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limit Orders vs Marketable Orders in a Polymarket Bot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When should the bot provide liquidity?&lt;/p&gt;

&lt;p&gt;When should it take liquidity?&lt;/p&gt;

&lt;p&gt;How much does execution probability matter?&lt;/p&gt;

&lt;p&gt;And when is getting filled more important than getting the perfect price?&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;I publish practical Polymarket bot development and experiments on GitHub.&lt;/p&gt;

&lt;p&gt;My Polymarket TWAP trading bot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ruudkoeyvoets/polymarket-trading-bot-twap" rel="noopener noreferrer"&gt;https://github.com/ruudkoeyvoets/polymarket-trading-bot-twap&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the Development
&lt;/h2&gt;

&lt;p&gt;I also share Polymarket bot development, execution experiments, and technical research on YouTube:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/@std0d" rel="noopener noreferrer"&gt;https://www.youtube.com/@std0d&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This article is for educational and software-development purposes only and is not financial advice. Automated trading involves substantial risk. No strategy, bot, or execution technique guarantees profit.&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>trading</category>
      <category>algorithmictrading</category>
      <category>web3</category>
    </item>
    <item>
      <title>Polymarket Bot: Practical Order Execution, Imbalance, and Liquidity</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Wed, 26 Aug 2026 05:24:37 +0000</pubDate>
      <link>https://dev.to/borntoup/polymarket-bot-practical-order-execution-imbalance-and-liquidity-1g64</link>
      <guid>https://dev.to/borntoup/polymarket-bot-practical-order-execution-imbalance-and-liquidity-1g64</guid>
      <description>&lt;p&gt;Building a &lt;strong&gt;Polymarket bot&lt;/strong&gt; is not simply about finding a trading signal and sending an order.&lt;/p&gt;

&lt;p&gt;The real challenge starts after the signal.&lt;/p&gt;

&lt;p&gt;A bot may correctly identify an opportunity, but the execution can still fail because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Poor liquidity&lt;/li&gt;
&lt;li&gt;Order-book imbalance&lt;/li&gt;
&lt;li&gt;Slippage&lt;/li&gt;
&lt;li&gt;Stale market data&lt;/li&gt;
&lt;li&gt;Bad order timing&lt;/li&gt;
&lt;li&gt;Incorrect order type&lt;/li&gt;
&lt;li&gt;Partial fills&lt;/li&gt;
&lt;li&gt;Excessive market impact&lt;/li&gt;
&lt;li&gt;Position imbalance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After working through these problems, I started looking at the &lt;strong&gt;Polymarket bot&lt;/strong&gt; as two separate systems:&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Should I trade?&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;How should I trade?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article focuses on the second part.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Polymarket Bot Actually Needs to Decide
&lt;/h2&gt;

&lt;p&gt;Suppose the strategy generates:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY YES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That is not enough information for the execution engine.&lt;/p&gt;

&lt;p&gt;The bot still needs to determine:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Price
Size
Order type
Timing
Available liquidity
Expected slippage
Current position
Current exposure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The same signal can produce completely different results depending on how it is executed.&lt;/p&gt;

&lt;p&gt;That is why I consider order execution one of the most important parts of a Polymarket bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limit Orders vs Aggressive Execution
&lt;/h2&gt;

&lt;p&gt;A limit order gives the bot control over the maximum price it is willing to pay.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best bid = 0.48
Best ask = 0.51
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The strategy might decide:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum entry = 0.49
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot places:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY YES @ 0.49
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now it waits for a seller.&lt;/p&gt;

&lt;p&gt;This protects the entry price, but there is a cost.&lt;/p&gt;

&lt;p&gt;The market might move:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.50
  ↓
0.52
  ↓
0.55
  ↓
0.58
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The order never fills.&lt;/p&gt;

&lt;p&gt;The bot protected itself from paying too much, but the opportunity disappeared.&lt;/p&gt;

&lt;p&gt;This creates an important execution question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is missing the trade worse than paying the spread and taking available liquidity?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is no universal answer.&lt;/p&gt;

&lt;p&gt;It depends on the expected edge, market conditions, liquidity, and strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aggressive Execution
&lt;/h2&gt;

&lt;p&gt;Sometimes the signal has a very short lifetime.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Market moves
  ↓
Edge disappears
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Waiting for a passive order can cause the bot to miss the opportunity.&lt;/p&gt;

&lt;p&gt;Aggressive execution can solve the timing problem, but it introduces other costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spread&lt;/li&gt;
&lt;li&gt;Slippage&lt;/li&gt;
&lt;li&gt;Market impact&lt;/li&gt;
&lt;li&gt;Liquidity consumption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So one useful rule is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected Edge &amp;gt; Expected Execution Cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the edge is smaller than the expected execution cost, the trade may no longer be attractive.&lt;/p&gt;

&lt;h2&gt;
  
  
  FOK and FAK
&lt;/h2&gt;

&lt;p&gt;Execution behavior matters too.&lt;/p&gt;

&lt;h3&gt;
  
  
  FOK
&lt;/h3&gt;

&lt;p&gt;FOK means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fill or Kill&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The order must be completely filled immediately or cancelled.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 100

Available = 100

→ Fill 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 100

Available = 60

→ Cancel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This can be useful when partial execution would make the strategy invalid.&lt;/p&gt;

&lt;h3&gt;
  
  
  FAK
&lt;/h3&gt;

&lt;p&gt;FAK means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fill and Kill&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The immediately available quantity is filled and the remaining quantity is cancelled.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 100

Available = 60

→ Fill 60
→ Cancel remaining 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;FAK can make sense when partial execution is still useful.&lt;/p&gt;

&lt;p&gt;The important point is that the Polymarket bot should choose the execution behavior according to the strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Look Only at the Last Price
&lt;/h2&gt;

&lt;p&gt;A common mistake is to build a Polymarket bot around the last traded price.&lt;/p&gt;

&lt;p&gt;The order book contains much more information.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BIDS

0.48 → 100
0.47 → 300
0.46 → 500

ASKS

0.52 → 50
0.53 → 100
0.54 → 400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now the bot can evaluate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best bid&lt;/li&gt;
&lt;li&gt;Best ask&lt;/li&gt;
&lt;li&gt;Spread&lt;/li&gt;
&lt;li&gt;Depth&lt;/li&gt;
&lt;li&gt;Available liquidity&lt;/li&gt;
&lt;li&gt;Expected execution price&lt;/li&gt;
&lt;li&gt;Potential price impact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The order book should be part of the bot's current market state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Order-Book Imbalance
&lt;/h2&gt;

&lt;p&gt;One of the practical metrics I look at is order-book imbalance.&lt;/p&gt;

&lt;p&gt;A simple calculation is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imbalance =
(bidVolume - askVolume)
/
(bidVolume + askVolume)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bidVolume = 800
askVolume = 200

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

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

&lt;/div&gt;

&lt;p&gt;There is significantly more visible bid volume than ask volume within the selected depth.&lt;/p&gt;

&lt;p&gt;But there is an important warning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imbalance is not automatically a BUY signal.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is one of the easiest mistakes to make when developing a Polymarket bot.&lt;/p&gt;

&lt;p&gt;An imbalance can disappear quickly.&lt;/p&gt;

&lt;p&gt;Orders can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cancelled&lt;/li&gt;
&lt;li&gt;Replaced&lt;/li&gt;
&lt;li&gt;Temporary&lt;/li&gt;
&lt;li&gt;Concentrated at one price&lt;/li&gt;
&lt;li&gt;Too far from the current execution price&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I would not build a strategy like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (imbalance &amp;gt; 0.5) {
    buy();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and assume the result will be reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the Depth
&lt;/h2&gt;

&lt;p&gt;The bot should have a consistent definition of imbalance.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best bid
+
5 bid levels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;versus:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best ask
+
5 ask levels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then calculate the imbalance.&lt;/p&gt;

&lt;p&gt;A simple implementation could be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateImbalance(
  bidVolume: number,
  askVolume: number
) {
  const total = bidVolume + askVolume;

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

  return (bidVolume - askVolume) / total;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The exact depth depends on the strategy.&lt;/p&gt;

&lt;p&gt;What matters is that the bot consistently measures the same thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persistence Matters
&lt;/h2&gt;

&lt;p&gt;A single imbalance snapshot can be misleading.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 → +0.70
t1 → +0.05
t2 → -0.30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The imbalance disappeared almost immediately.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 → +0.70
t1 → +0.68
t2 → +0.72
t3 → +0.65
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The second condition is more interesting.&lt;/p&gt;

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

&lt;p&gt;Because the imbalance persisted.&lt;/p&gt;

&lt;p&gt;So instead of measuring only:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance Magnitude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;the bot can also measure:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance Persistence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This gives the execution engine more context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imbalance Needs Context
&lt;/h2&gt;

&lt;p&gt;I would never treat imbalance as an isolated signal.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance ↑
Price ↑
Trade flow ↑
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That is different from:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance ↑
Price ↓
Trade flow ↓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot should consider multiple pieces of market state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order-book imbalance&lt;/li&gt;
&lt;li&gt;Price movement&lt;/li&gt;
&lt;li&gt;Recent trades&lt;/li&gt;
&lt;li&gt;Spread&lt;/li&gt;
&lt;li&gt;Liquidity&lt;/li&gt;
&lt;li&gt;Depth&lt;/li&gt;
&lt;li&gt;Time remaining&lt;/li&gt;
&lt;li&gt;Current position&lt;/li&gt;
&lt;li&gt;Existing orders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to find one magic indicator.&lt;/p&gt;

&lt;p&gt;The goal is to build a better market-state model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Large Orders and Slippage
&lt;/h2&gt;

&lt;p&gt;Now consider a larger order.&lt;/p&gt;

&lt;p&gt;Suppose the ask side contains:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.50 → 20
0.51 → 30
0.52 → 50
0.53 → 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot wants to buy 150.&lt;/p&gt;

&lt;p&gt;It cannot assume:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;150 × 0.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The actual execution could be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;20 @ 0.50
30 @ 0.51
50 @ 0.52
50 @ 0.53
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The average execution price is now much higher.&lt;/p&gt;

&lt;p&gt;This is why a Polymarket bot should estimate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Available depth&lt;/li&gt;
&lt;li&gt;Expected average execution price&lt;/li&gt;
&lt;li&gt;Slippage&lt;/li&gt;
&lt;li&gt;Price impact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;before submitting larger orders.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the Bot Pushes the Market
&lt;/h2&gt;

&lt;p&gt;Large marketable orders can consume multiple levels of liquidity.&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ASK

0.50 → 100
0.51 → 100
0.52 → 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a large buy:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ASK

0.52 → 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The best ask moved because liquidity was consumed.&lt;/p&gt;

&lt;p&gt;But I would not automatically call this momentum.&lt;/p&gt;

&lt;p&gt;There is a difference between:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Liquidity consumption
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Other traders repricing the market
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That distinction is important when interpreting order flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Let the Bot Chase Its Own Order
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Large order
  ↓
Liquidity consumed
  ↓
Price moves
  ↓
Bot continues buying
  ↓
Average entry gets worse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The original signal may still be correct.&lt;/p&gt;

&lt;p&gt;The execution is what failed.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Available Depth
+
Expected Edge
+
Maximum Slippage
+
Current Exposure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A good execution engine should know when to stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Order Timing
&lt;/h2&gt;

&lt;p&gt;One of the most overlooked parts of a Polymarket bot is timing.&lt;/p&gt;

&lt;p&gt;A signal is generated at one point in time.&lt;/p&gt;

&lt;p&gt;The order may be submitted later.&lt;/p&gt;

&lt;p&gt;The market may have changed in between.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00:00.000
Signal generated

10:00:00.100
Order created

10:00:00.180
Order submitted

10:00:00.250
Order matched
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The market state at 10:00:00.000 may no longer exist at 10:00:00.250.&lt;/p&gt;

&lt;p&gt;This creates a signal-to-execution race condition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Revalidate Before Execution
&lt;/h2&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I prefer:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Revalidate Market
  ↓
Revalidate Price
  ↓
Revalidate Liquidity
  ↓
Revalidate Position
  ↓
Revalidate Risk
  ↓
Submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The closer the execution is to the signal, the less likely the bot is to act on stale information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split and Merge
&lt;/h2&gt;

&lt;p&gt;Split and merge are another interesting part of building a Polymarket bot.&lt;/p&gt;

&lt;p&gt;They are especially relevant to inventory management.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Collateral
   ↓
 SPLIT
   ↓
 YES + NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This can be useful when a strategy needs inventory on both outcomes.&lt;/p&gt;

&lt;p&gt;Now consider a bot holding:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 YES
100 NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The matching positions can potentially be merged:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 YES
   +
100 NO
   ↓
100 collateral
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the bot instead has:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 YES
50 NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;only the matching amount can be merged:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50 YES
   +
50 NO
   ↓
50 collateral
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The remaining YES position is still open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split and Merge Are Inventory Tools
&lt;/h2&gt;

&lt;p&gt;I don't think of split and merge as direct trading signals.&lt;/p&gt;

&lt;p&gt;I think of them as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inventory Management
       +
Position Management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot can ask:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do I need YES + NO inventory?

→ Consider SPLIT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do I have matching YES + NO?

→ Consider MERGE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The decision still needs to consider the current position, costs, timing, and execution conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Order Lifecycle
&lt;/h2&gt;

&lt;p&gt;Submitting an order is not the end of the execution process.&lt;/p&gt;

&lt;p&gt;The bot needs to track what happens after submission.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEW
  ↓
SUBMITTED
  ↓
OPEN
  ↓
PARTIALLY FILLED
  ↓
FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SUBMITTED
  ↓
REJECTED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPEN
  ↓
MARKET MOVES
  ↓
CANCEL
  ↓
REPLACE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is why I prefer treating order management as a state machine.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEW
SUBMITTED
OPEN
PARTIALLY_FILLED
FILLED
CANCELLED
REJECTED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Explicit states make the execution engine much easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Polymarket Bot Execution Checklist
&lt;/h2&gt;

&lt;p&gt;Before submitting an important order, I want to check:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Market is active
[ ] Market data is fresh
[ ] Order book is fresh
[ ] Spread is acceptable
[ ] Liquidity is sufficient
[ ] Expected slippage is acceptable
[ ] Imbalance is meaningful
[ ] Imbalance is persistent
[ ] Signal is still valid
[ ] Position size is acceptable
[ ] Exposure limit is not exceeded
[ ] Price is still valid
[ ] Order size is valid
[ ] Execution type is appropriate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Only after those checks:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PLACE ORDER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Complete Polymarket Bot Execution Flow
&lt;/h2&gt;

&lt;p&gt;The practical execution architecture looks like:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MARKET DATA
     ↓
ORDER BOOK
     ↓
TWAP STATE
     ↓
TRADE FLOW
     ↓
IMBALANCE
     ↓
STRATEGY
     ↓
SIGNAL
     ↓
FRESHNESS CHECK
     ↓
LIQUIDITY CHECK
     ↓
SLIPPAGE CHECK
     ↓
POSITION CHECK
     ↓
EXECUTION TYPE
     ↓
ORDER SUBMIT
     ↓
FILL MONITOR
     ↓
CANCEL / REPLACE
     ↓
POSITION UPDATE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is very different from:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal → Buy
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;The strategy is only half of a Polymarket bot.&lt;/p&gt;

&lt;p&gt;The other half is execution.&lt;/p&gt;

&lt;p&gt;A serious Polymarket bot needs to answer two questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should I trade?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How should I execute?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Limit orders provide price control.&lt;/p&gt;

&lt;p&gt;Aggressive execution provides speed.&lt;/p&gt;

&lt;p&gt;FOK provides all-or-nothing execution.&lt;/p&gt;

&lt;p&gt;FAK allows partial immediate execution.&lt;/p&gt;

&lt;p&gt;Order-book imbalance provides useful context, but it should not automatically become a BUY or SELL signal.&lt;/p&gt;

&lt;p&gt;Split can help create inventory.&lt;/p&gt;

&lt;p&gt;Merge can help manage matching positions.&lt;/p&gt;

&lt;p&gt;And execution timing can be just as important as the original trading signal.&lt;/p&gt;

&lt;p&gt;The execution process I care about is:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Validate
  ↓
Measure Liquidity
  ↓
Check Imbalance
  ↓
Estimate Impact
  ↓
Choose Order Type
  ↓
Execute
  ↓
Monitor
  ↓
Reconcile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's where a Polymarket bot becomes an actual execution system rather than just a strategy script.&lt;/p&gt;

&lt;p&gt;If you're building a Polymarket bot, the trading signal is only the beginning.&lt;/p&gt;

&lt;p&gt;The real engineering challenge is what happens between:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"I found an opportunity"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"The order was actually executed."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Automated trading involves financial risk. No execution technique guarantees profit, and historical or simulated results do not guarantee future performance.&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>tradingbot</category>
      <category>programming</category>
      <category>web3</category>
    </item>
    <item>
      <title>How I Actually Execute Orders in a Polymarket Bot</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Mon, 24 Aug 2026 18:33:47 +0000</pubDate>
      <link>https://dev.to/borntoup/how-i-actually-execute-orders-in-a-polymarket-bot-2cp3</link>
      <guid>https://dev.to/borntoup/how-i-actually-execute-orders-in-a-polymarket-bot-2cp3</guid>
      <description>&lt;p&gt;Most Polymarket bot tutorials focus on the strategy.&lt;/p&gt;

&lt;p&gt;Find a signal.&lt;/p&gt;

&lt;p&gt;Calculate an edge.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (signal) {
  placeOrder();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But that is where the real problem starts.&lt;/p&gt;

&lt;p&gt;When building a practical &lt;strong&gt;Polymarket bot&lt;/strong&gt;, detecting an opportunity is only one part of the system.&lt;/p&gt;

&lt;p&gt;The harder question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do you actually execute that opportunity correctly?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You need to answer questions like:&lt;/p&gt;

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

&lt;p&gt;This is the practical execution layer of a Polymarket trading bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategy vs Execution
&lt;/h2&gt;

&lt;p&gt;I separate a Polymarket bot into two major components.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Should I trade?&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;How should I trade?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The strategy might generate:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY YES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But the execution engine still needs to determine:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Price
Size
Order type
Timing
Liquidity
Slippage
Position
Exposure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A good strategy can still lose its edge because of poor execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limit Orders
&lt;/h2&gt;

&lt;p&gt;A limit order gives the bot control over the maximum acceptable price.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best bid = 0.48
Best ask = 0.51
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The strategy determines:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Maximum entry price = 0.49
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot could place:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY YES @ 0.49
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now the order waits for a matching seller.&lt;/p&gt;

&lt;p&gt;The lifecycle could look like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST
  ↓
PARTIAL FILL
  ↓
FULL FILL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST
  ↓
NO FILL
  ↓
CANCEL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Limit orders are useful when price is more important than immediate execution.&lt;/p&gt;

&lt;p&gt;But there is an important trade-off.&lt;/p&gt;

&lt;p&gt;Suppose the market moves:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.50
  ↓
0.52
  ↓
0.55
  ↓
0.58
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The limit order never fills.&lt;/p&gt;

&lt;p&gt;The bot protected its entry price, but it missed the opportunity.&lt;/p&gt;

&lt;p&gt;So the real question isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are limit orders better?&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Is missing the trade worse than paying the spread and execution cost?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That depends on the strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Immediate Execution Has a Different Problem
&lt;/h2&gt;

&lt;p&gt;Sometimes a signal has a very short lifetime.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Market moves
  ↓
Edge disappears
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Waiting for a passive limit order can mean missing the opportunity.&lt;/p&gt;

&lt;p&gt;The bot may instead take available liquidity.&lt;/p&gt;

&lt;p&gt;But aggressive execution introduces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spread cost&lt;/li&gt;
&lt;li&gt;Slippage&lt;/li&gt;
&lt;li&gt;Market impact&lt;/li&gt;
&lt;li&gt;Liquidity consumption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The execution engine should therefore compare:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected Edge
      &amp;gt;
Execution Cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the expected edge is too small, crossing the book can destroy the trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  FOK vs FAK
&lt;/h2&gt;

&lt;p&gt;Execution behavior matters too.&lt;/p&gt;

&lt;h3&gt;
  
  
  FOK
&lt;/h3&gt;

&lt;p&gt;FOK means &lt;strong&gt;Fill or Kill&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The entire order must be filled immediately.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 100

Available = 100

→ Fill 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 100

Available = 60

→ Cancel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;FOK can make sense when partial execution would make the trade invalid.&lt;/p&gt;

&lt;h3&gt;
  
  
  FAK
&lt;/h3&gt;

&lt;p&gt;FAK means &lt;strong&gt;Fill and Kill&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The available quantity is filled immediately and the remainder is cancelled.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY 100

Available = 60

→ Fill 60
→ Cancel remaining 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;FAK can make sense when partial execution is still useful.&lt;/p&gt;

&lt;p&gt;The important part is not choosing one order type everywhere.&lt;/p&gt;

&lt;p&gt;The execution type should match the strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Look Only at the Last Price
&lt;/h2&gt;

&lt;p&gt;One of the biggest mistakes when building a Polymarket bot is looking only at the last traded price.&lt;/p&gt;

&lt;p&gt;Consider this order book:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BIDS

0.48 → 100
0.47 → 300
0.46 → 500

ASKS

0.52 → 50
0.53 → 100
0.54 → 400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot can now evaluate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best bid&lt;/li&gt;
&lt;li&gt;Best ask&lt;/li&gt;
&lt;li&gt;Spread&lt;/li&gt;
&lt;li&gt;Depth&lt;/li&gt;
&lt;li&gt;Available liquidity&lt;/li&gt;
&lt;li&gt;Potential execution price&lt;/li&gt;
&lt;li&gt;Potential price impact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The order book is part of the bot's current market state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Order-Book Imbalance
&lt;/h2&gt;

&lt;p&gt;One metric I find useful is order-book imbalance.&lt;/p&gt;

&lt;p&gt;A simple calculation is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imbalance =
(bidVolume - askVolume)
/
(bidVolume + askVolume)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bidVolume = 800
askVolume = 200

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

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

&lt;/div&gt;

&lt;p&gt;There is significantly more visible bid volume than ask volume within the selected depth.&lt;/p&gt;

&lt;p&gt;But this is where many trading bots make a mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imbalance is not automatically a BUY signal.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A large imbalance can disappear very quickly.&lt;/p&gt;

&lt;p&gt;Orders can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cancelled&lt;/li&gt;
&lt;li&gt;Replaced&lt;/li&gt;
&lt;li&gt;Temporary&lt;/li&gt;
&lt;li&gt;Concentrated at one price&lt;/li&gt;
&lt;li&gt;Outside the relevant execution range&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I would not simply build:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (imbalance &amp;gt; 0.5) {
    buy();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and call it a complete trading strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define a Depth Window
&lt;/h2&gt;

&lt;p&gt;Instead of calculating imbalance over an arbitrary amount of the order book, define a consistent depth.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Best bid
  +
5 bid levels

versus

Best ask
  +
5 ask levels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then calculate the imbalance.&lt;/p&gt;

&lt;p&gt;A simple implementation could look like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateImbalance(
  bidVolume: number,
  askVolume: number
) {
  const total = bidVolume + askVolume;

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

  return (bidVolume - askVolume) / total;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The exact depth should depend on the market and strategy.&lt;/p&gt;

&lt;p&gt;The important thing is consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persistence Matters
&lt;/h2&gt;

&lt;p&gt;Checking imbalance once is often not enough.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 → +0.70
t1 → +0.05
t2 → -0.30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The imbalance disappeared almost immediately.&lt;/p&gt;

&lt;p&gt;Compare that with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0 → +0.70
t1 → +0.68
t2 → +0.72
t3 → +0.65
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The second condition is much more interesting because the imbalance persisted.&lt;/p&gt;

&lt;p&gt;This means a bot can track:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance Magnitude
         +
Imbalance Duration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A single snapshot can be noise.&lt;/p&gt;

&lt;p&gt;A persistent condition can provide more useful information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imbalance Needs Context
&lt;/h2&gt;

&lt;p&gt;I would not interpret imbalance by itself.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance ↑
Price ↑
Trade flow ↑
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is different from:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imbalance ↑
Price ↓
Trade flow ↓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The execution engine should combine order-book information with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Price movement&lt;/li&gt;
&lt;li&gt;Recent trades&lt;/li&gt;
&lt;li&gt;Spread&lt;/li&gt;
&lt;li&gt;Liquidity&lt;/li&gt;
&lt;li&gt;Depth&lt;/li&gt;
&lt;li&gt;Time remaining&lt;/li&gt;
&lt;li&gt;Current position&lt;/li&gt;
&lt;li&gt;Existing orders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The order book needs context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Large Orders Create Another Problem
&lt;/h2&gt;

&lt;p&gt;Suppose the ask side looks like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.50 → 20
0.51 → 30
0.52 → 50
0.53 → 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot wants to buy 150.&lt;/p&gt;

&lt;p&gt;It cannot assume:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;150 × 0.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The actual execution might be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;20 @ 0.50
30 @ 0.51
50 @ 0.52
50 @ 0.53
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now the average execution price is much worse.&lt;/p&gt;

&lt;p&gt;This is why a Polymarket trading bot should estimate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Available depth&lt;/li&gt;
&lt;li&gt;Expected average price&lt;/li&gt;
&lt;li&gt;Slippage&lt;/li&gt;
&lt;li&gt;Price impact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;before sending large orders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Order Push and Liquidity Consumption
&lt;/h2&gt;

&lt;p&gt;A large marketable order can consume multiple levels of liquidity.&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ASK

0.50 → 100
0.51 → 100
0.52 → 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a large buy:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ASK

0.52 → 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The best ask moved because liquidity was consumed.&lt;/p&gt;

&lt;p&gt;But I would not automatically call this momentum.&lt;/p&gt;

&lt;p&gt;There is a difference between:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Liquidity consumption
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Other market participants repricing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That distinction matters when building a Polymarket bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Let the Bot Make Its Own Execution Worse
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Large order
  ↓
Consume liquidity
  ↓
Price moves
  ↓
Bot continues buying
  ↓
Average entry becomes worse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The original signal might still be correct.&lt;/p&gt;

&lt;p&gt;The execution is the problem.&lt;/p&gt;

&lt;p&gt;Order size should therefore consider:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Available Depth
      +
Expected Edge
      +
Maximum Slippage
      +
Current Exposure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A good execution engine should know when to stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should the Bot Actually Place the Order?
&lt;/h2&gt;

&lt;p&gt;A signal does not always mean:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUY NOW
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I prefer an execution flow like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Update
      ↓
Update State
      ↓
Check TWAP
      ↓
Check Order Book
      ↓
Check Imbalance
      ↓
Check Spread
      ↓
Check Liquidity
      ↓
Check Position
      ↓
Generate Signal
      ↓
Revalidate
      ↓
Submit Order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The important step is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revalidate.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal-to-Execution Race Conditions
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10:00:00.000
Signal generated

10:00:00.100
Order created

10:00:00.180
Order submitted

10:00:00.250
Order matched
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The market state at the time of the signal may be completely different from the state when the order is matched.&lt;/p&gt;

&lt;p&gt;Before submitting an important order, the execution layer should re-check:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market status
Price
Liquidity
Spread
Position
Exposure
Signal freshness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Revalidate Market
  ↓
Revalidate Price
  ↓
Revalidate Liquidity
  ↓
Revalidate Risk
  ↓
Submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This helps prevent the bot from executing stale signals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split
&lt;/h2&gt;

&lt;p&gt;Split is useful for inventory management.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Collateral
    ↓
  SPLIT
    ↓
  YES + NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This can be useful when a bot needs inventory on both sides of a market.&lt;/p&gt;

&lt;p&gt;For example, a market-making system may need:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YES inventory
      +
NO inventory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Split can provide the paired outcome inventory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge
&lt;/h2&gt;

&lt;p&gt;Merge works in the opposite direction.&lt;/p&gt;

&lt;p&gt;Suppose the bot has:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 YES
100 NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The matching positions can potentially be merged:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 YES
    +
100 NO
    ↓
100 collateral
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But if the bot has:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 YES
50 NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;only the matching portion can be merged:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50 YES
    +
50 NO
    ↓
50 collateral
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The remaining:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50 YES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;is still an open position.&lt;/p&gt;

&lt;p&gt;This makes split and merge useful as inventory-management mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split and Merge Are Not Trading Signals
&lt;/h2&gt;

&lt;p&gt;I don't think of split and merge as automatic BUY or SELL signals.&lt;/p&gt;

&lt;p&gt;They are better viewed as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inventory Management
        +
Position Management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The bot can ask:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do I need YES + NO inventory?

→ Consider SPLIT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do I have matching YES + NO?

→ Consider MERGE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The decision still needs to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Costs&lt;/li&gt;
&lt;li&gt;Timing&lt;/li&gt;
&lt;li&gt;Liquidity&lt;/li&gt;
&lt;li&gt;Collateral&lt;/li&gt;
&lt;li&gt;Current inventory&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Execution Checklist
&lt;/h2&gt;

&lt;p&gt;Before submitting an important order, I want the bot to check:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Market is active
[ ] Market data is fresh
[ ] Order book is fresh
[ ] Spread is acceptable
[ ] Liquidity is sufficient
[ ] Expected slippage is acceptable
[ ] Imbalance is meaningful
[ ] Imbalance is persistent
[ ] Signal is still valid
[ ] Position size is acceptable
[ ] Exposure limit is not exceeded
[ ] Price is still valid
[ ] Order size is valid
[ ] Execution type is appropriate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Only after those checks:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PLACE ORDER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The Order Lifecycle Doesn't Stop at Submission
&lt;/h2&gt;

&lt;p&gt;Placing the order is not the end.&lt;/p&gt;

&lt;p&gt;The bot needs to monitor:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SUBMITTED
   ↓
OPEN
   ↓
PARTIALLY_FILLED
   ↓
FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SUBMITTED
   ↓
REJECTED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPEN
   ↓
MARKET MOVES
   ↓
CANCEL
   ↓
REPLACE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is why order management needs its own state machine.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type OrderState =
  | "NEW"
  | "SUBMITTED"
  | "OPEN"
  | "PARTIALLY_FILLED"
  | "FILLED"
  | "CANCELLED"
  | "REJECTED";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Explicit order states make the execution logic easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Polymarket Bot Execution Flow
&lt;/h2&gt;

&lt;p&gt;The practical flow becomes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MARKET DATA
     ↓
ORDER BOOK
     ↓
TWAP STATE
     ↓
TRADE FLOW
     ↓
IMBALANCE
     ↓
STRATEGY
     ↓
SIGNAL
     ↓
FRESHNESS CHECK
     ↓
LIQUIDITY CHECK
     ↓
SLIPPAGE CHECK
     ↓
POSITION CHECK
     ↓
EXECUTION TYPE
     ↓
ORDER SUBMIT
     ↓
FILL MONITOR
     ↓
CANCEL / REPLACE
     ↓
POSITION UPDATE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is very different from:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal → Buy
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;The strategy is only half of a Polymarket bot.&lt;/p&gt;

&lt;p&gt;The other half is execution.&lt;/p&gt;

&lt;p&gt;A serious Polymarket bot needs to understand:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Should I trade?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How should I execute?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Limit orders provide price control.&lt;/p&gt;

&lt;p&gt;Immediate execution provides speed.&lt;/p&gt;

&lt;p&gt;FOK provides all-or-nothing execution.&lt;/p&gt;

&lt;p&gt;FAK allows partial immediate execution.&lt;/p&gt;

&lt;p&gt;Order-book imbalance provides useful context, but it should not automatically become a BUY or SELL signal.&lt;/p&gt;

&lt;p&gt;Split can help create inventory.&lt;/p&gt;

&lt;p&gt;Merge can help manage matching positions.&lt;/p&gt;

&lt;p&gt;And execution timing can be just as important as the original trading signal.&lt;/p&gt;

&lt;p&gt;The execution process I care about is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signal
  ↓
Validate
  ↓
Measure Liquidity
  ↓
Check Imbalance
  ↓
Estimate Impact
  ↓
Choose Order Type
  ↓
Execute
  ↓
Monitor
  ↓
Reconcile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's where a Polymarket bot becomes an actual execution system rather than just a strategy script.&lt;/p&gt;

&lt;p&gt;Automated trading involves financial risk. No execution technique guarantees profit, and historical or simulated results do not guarantee future performance.&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>tradingbot</category>
      <category>web3</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building a Polymarket Bot: From Real-Time Data to Automated Execution</title>
      <dc:creator>BornToWin</dc:creator>
      <pubDate>Wed, 19 Aug 2026 15:34:12 +0000</pubDate>
      <link>https://dev.to/borntoup/building-a-polymarket-bot-from-real-time-data-to-automated-execution-2354</link>
      <guid>https://dev.to/borntoup/building-a-polymarket-bot-from-real-time-data-to-automated-execution-2354</guid>
      <description>&lt;p&gt;A Polymarket bot can be much more than a script that places orders.&lt;/p&gt;

&lt;p&gt;A well-designed Polymarket bot can monitor markets, process real-time data, analyze market conditions, detect opportunities, manage risk, and automatically execute predefined actions.&lt;/p&gt;

&lt;p&gt;That's the type of system I'm interested in building.&lt;/p&gt;

&lt;p&gt;The basic architecture looks like this:&lt;/p&gt;

&lt;p&gt;Real-Time Market Data&lt;br&gt;
↓&lt;br&gt;
Market Analysis&lt;br&gt;
↓&lt;br&gt;
TWAP / Strategy Logic&lt;br&gt;
↓&lt;br&gt;
Signal Generation&lt;br&gt;
↓&lt;br&gt;
Risk Management&lt;br&gt;
↓&lt;br&gt;
Automated Execution&lt;br&gt;
↓&lt;br&gt;
Monitoring&lt;/p&gt;

&lt;p&gt;The important part isn't one individual component.&lt;/p&gt;

&lt;p&gt;It's how all of these components work together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Polymarket Bot?
&lt;/h2&gt;

&lt;p&gt;At a high level, a Polymarket bot continuously observes markets and makes decisions according to predefined rules.&lt;/p&gt;

&lt;p&gt;A typical workflow looks like:&lt;/p&gt;

&lt;p&gt;Market Data&lt;br&gt;
↓&lt;br&gt;
Data Validation&lt;br&gt;
↓&lt;br&gt;
Market Analysis&lt;br&gt;
↓&lt;br&gt;
Opportunity Detection&lt;br&gt;
↓&lt;br&gt;
Risk Check&lt;br&gt;
↓&lt;br&gt;
Execution&lt;/p&gt;

&lt;p&gt;Depending on the use case, a Polymarket bot can be designed for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automated trading&lt;/li&gt;
&lt;li&gt;Market monitoring&lt;/li&gt;
&lt;li&gt;Price alerts&lt;/li&gt;
&lt;li&gt;Strategy execution&lt;/li&gt;
&lt;li&gt;TWAP analysis&lt;/li&gt;
&lt;li&gt;Portfolio monitoring&lt;/li&gt;
&lt;li&gt;Market-data collection&lt;/li&gt;
&lt;li&gt;Automated order execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why I prefer thinking about it as a Polymarket bot system rather than simply an order-placement script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-Time Data Is the Foundation
&lt;/h2&gt;

&lt;p&gt;A Polymarket bot is only as useful as the data it receives.&lt;/p&gt;

&lt;p&gt;The system needs to continuously process information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Market prices&lt;/li&gt;
&lt;li&gt;Order-book changes&lt;/li&gt;
&lt;li&gt;Trading activity&lt;/li&gt;
&lt;li&gt;Timestamps&lt;/li&gt;
&lt;li&gt;Market status&lt;/li&gt;
&lt;li&gt;Position information&lt;/li&gt;
&lt;li&gt;Execution events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data pipeline also needs to handle failures.&lt;/p&gt;

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

&lt;p&gt;WebSocket disconnect&lt;br&gt;
↓&lt;br&gt;
Reconnect&lt;br&gt;
↓&lt;br&gt;
Refresh state&lt;br&gt;
↓&lt;br&gt;
Validate data&lt;br&gt;
↓&lt;br&gt;
Resume&lt;/p&gt;

&lt;p&gt;A bot shouldn't blindly continue operating after losing its market-data connection.&lt;/p&gt;

&lt;p&gt;Data freshness is part of the trading logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  TWAP Analysis
&lt;/h2&gt;

&lt;p&gt;One area I've been experimenting with is TWAP-based market analysis.&lt;/p&gt;

&lt;p&gt;TWAP introduces a time dimension to the strategy.&lt;/p&gt;

&lt;p&gt;Instead of looking only at:&lt;/p&gt;

&lt;p&gt;"What's the current price?"&lt;/p&gt;

&lt;p&gt;the system can ask:&lt;/p&gt;

&lt;p&gt;"How is the average price evolving during the relevant time window?"&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;Price Observations&lt;br&gt;
↓&lt;br&gt;
TWAP Calculation&lt;br&gt;
↓&lt;br&gt;
Current TWAP&lt;br&gt;
↓&lt;br&gt;
Projected TWAP&lt;br&gt;
↓&lt;br&gt;
Market Analysis&lt;/p&gt;

&lt;p&gt;As new observations arrive, the bot can update its internal market state.&lt;/p&gt;

&lt;p&gt;This makes the system dynamic instead of relying on a single price snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal Generation
&lt;/h2&gt;

&lt;p&gt;Once the bot has reliable market data, it can evaluate predefined conditions.&lt;/p&gt;

&lt;p&gt;The process can be:&lt;/p&gt;

&lt;p&gt;Market State&lt;br&gt;
↓&lt;br&gt;
Strategy Rules&lt;br&gt;
↓&lt;br&gt;
Signal&lt;/p&gt;

&lt;p&gt;A signal might contain information such as:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  market: "...",&lt;br&gt;
  action: "BUY",&lt;br&gt;
  confidence: 0.72,&lt;br&gt;
  expectedEdge: 0.04&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The important design decision is that the strategy should generate the decision while another component handles execution.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Risk Management
&lt;/h2&gt;

&lt;p&gt;A signal doesn't automatically mean the bot should execute it.&lt;/p&gt;

&lt;p&gt;Before taking action, the bot can check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current exposure&lt;/li&gt;
&lt;li&gt;Position limits&lt;/li&gt;
&lt;li&gt;Available liquidity&lt;/li&gt;
&lt;li&gt;Market conditions&lt;/li&gt;
&lt;li&gt;Data freshness&lt;/li&gt;
&lt;li&gt;Existing orders&lt;/li&gt;
&lt;li&gt;Maximum trade size&lt;/li&gt;
&lt;li&gt;Strategy limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The workflow becomes:&lt;/p&gt;

&lt;p&gt;Signal&lt;br&gt;
↓&lt;br&gt;
Risk Check&lt;br&gt;
↓&lt;br&gt;
Approved?&lt;br&gt;
↓&lt;br&gt;
YES → Execute&lt;br&gt;
NO → Skip&lt;/p&gt;

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

&lt;p&gt;A good bot should know when not to act.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated Execution
&lt;/h2&gt;

&lt;p&gt;Once a signal passes the risk layer, the execution engine can interact with the Polymarket CLOB.&lt;/p&gt;

&lt;p&gt;Execution introduces its own challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order submission&lt;/li&gt;
&lt;li&gt;Order status&lt;/li&gt;
&lt;li&gt;Partial fills&lt;/li&gt;
&lt;li&gt;Order rejection&lt;/li&gt;
&lt;li&gt;Liquidity changes&lt;/li&gt;
&lt;li&gt;API errors&lt;/li&gt;
&lt;li&gt;Duplicate orders&lt;/li&gt;
&lt;li&gt;Network failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's why I don't want the whole system to be:&lt;/p&gt;

&lt;p&gt;if (signal) {&lt;br&gt;
  placeOrder();&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A production-oriented bot needs state, validation, error handling, and recovery logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring the Bot
&lt;/h2&gt;

&lt;p&gt;Automation without monitoring is difficult to trust.&lt;/p&gt;

&lt;p&gt;I want the system to record important events such as:&lt;/p&gt;

&lt;p&gt;MARKET_UPDATE&lt;br&gt;
TWAP_UPDATE&lt;br&gt;
SIGNAL_GENERATED&lt;br&gt;
RISK_CHECK&lt;br&gt;
ORDER_SUBMITTED&lt;br&gt;
ORDER_FILLED&lt;br&gt;
ORDER_FAILED&lt;br&gt;
DATA_STALE&lt;br&gt;
WEBSOCKET_DISCONNECTED&lt;br&gt;
WEBSOCKET_RECONNECTED&lt;/p&gt;

&lt;p&gt;This makes it possible to answer an important question:&lt;/p&gt;

&lt;p&gt;"Why did the Polymarket bot make this decision?"&lt;/p&gt;

&lt;p&gt;Without good logging, debugging a live system becomes much harder.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Architecture
&lt;/h2&gt;

&lt;p&gt;Real-Time Data&lt;br&gt;
↓&lt;br&gt;
Data Validation&lt;br&gt;
↓&lt;br&gt;
Market Analysis&lt;br&gt;
↓&lt;br&gt;
TWAP / Strategy&lt;br&gt;
↓&lt;br&gt;
Signal Engine&lt;br&gt;
↓&lt;br&gt;
Risk Management&lt;br&gt;
↓&lt;br&gt;
CLOB Execution&lt;br&gt;
↓&lt;br&gt;
Monitoring&lt;/p&gt;

&lt;p&gt;Each layer has a specific responsibility.&lt;/p&gt;

&lt;p&gt;That makes the system easier to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Develop&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;li&gt;Debug&lt;/li&gt;
&lt;li&gt;Scale&lt;/li&gt;
&lt;li&gt;Modify&lt;/li&gt;
&lt;li&gt;Monitor&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building a Bot vs. Building a System
&lt;/h2&gt;

&lt;p&gt;A simple Polymarket bot might be:&lt;/p&gt;

&lt;p&gt;IF condition&lt;br&gt;
THEN execute&lt;/p&gt;

&lt;p&gt;A more robust system asks:&lt;/p&gt;

&lt;p&gt;Is the market data fresh?&lt;/p&gt;

&lt;p&gt;Is this the correct market?&lt;/p&gt;

&lt;p&gt;What is the current market state?&lt;/p&gt;

&lt;p&gt;What does the strategy indicate?&lt;/p&gt;

&lt;p&gt;Is the opportunity large enough?&lt;/p&gt;

&lt;p&gt;Are we within risk limits?&lt;/p&gt;

&lt;p&gt;Do we already have an order?&lt;/p&gt;

&lt;p&gt;Is liquidity sufficient?&lt;/p&gt;

&lt;p&gt;Is execution currently possible?&lt;/p&gt;

&lt;p&gt;Should the bot act or wait?&lt;/p&gt;

&lt;p&gt;That's the difference I'm interested in.&lt;/p&gt;

&lt;p&gt;I'm not trying to build a bot that blindly executes every signal.&lt;/p&gt;

&lt;p&gt;I'm building Polymarket automation infrastructure that can make decisions based on real-time market conditions and predefined rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and Improving the System
&lt;/h2&gt;

&lt;p&gt;Before relying on a strategy in live conditions, I prefer to progressively test it:&lt;/p&gt;

&lt;p&gt;Backtest&lt;br&gt;
↓&lt;br&gt;
Out-of-Sample Testing&lt;br&gt;
↓&lt;br&gt;
Simulation&lt;br&gt;
↓&lt;br&gt;
Paper Trading&lt;br&gt;
↓&lt;br&gt;
Small Live Test&lt;/p&gt;

&lt;p&gt;The goal is to reduce assumptions at every stage.&lt;/p&gt;

&lt;p&gt;A strategy that works only with perfect data and perfect execution isn't enough.&lt;/p&gt;

&lt;p&gt;The real challenge is seeing whether the system continues to behave correctly when market conditions, liquidity, latency, and execution change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;I'm continuing to work on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polymarket bots&lt;/li&gt;
&lt;li&gt;TWAP-based strategies&lt;/li&gt;
&lt;li&gt;Real-time market data&lt;/li&gt;
&lt;li&gt;Automated execution&lt;/li&gt;
&lt;li&gt;CLOB infrastructure&lt;/li&gt;
&lt;li&gt;Risk-management systems&lt;/li&gt;
&lt;li&gt;Market monitoring&lt;/li&gt;
&lt;li&gt;Strategy testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part isn't simply making a bot execute.&lt;/p&gt;

&lt;p&gt;It's building a system that can:&lt;/p&gt;

&lt;p&gt;Observe → Analyze → Decide → Execute → Monitor → Recover&lt;/p&gt;

&lt;p&gt;automatically.&lt;/p&gt;

&lt;p&gt;If you're looking for someone to build a custom Polymarket bot, automated market-monitoring system, strategy engine, or execution infrastructure, that's the type of work I'm interested in.&lt;/p&gt;

&lt;p&gt;Automated trading involves financial risk. Historical results, backtests, and simulations do not guarantee future performance.&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>tradingbot</category>
      <category>programming</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
