How CloddsBot Performs Cross-Platform Arbitrage Detection Using Semantic Matching

CloddsBot identifies arbitrage opportunities across prediction market platforms by encoding market titles into vector embeddings and computing cosine similarity to match identical underlying events, then verifies these semantic matches before calculating cross-venue price spreads.

Cross-platform arbitrage detection using semantic matching is the core mechanism that enables the alsk1992/CloddsBot system to find identical prediction markets listed on different venues like Polymarket, Kalshi, and Manifold. The TypeScript implementation leverages vector embeddings to overcome platform-specific naming inconsistencies and surface genuine arbitrage edges. This article breaks down the exact source code implementation found in the repository's opportunity matching pipeline.

Semantic Matching Architecture

The Opportunity Matcher Core

The semantic matching logic resides in src/opportunity/matching.ts, where the matchMarkets function implements the primary detection algorithm. According to the alskk1992/CloddsBot source code, this component first attempts semantic matching using vector embeddings when the semanticEnabled flag is active, with a default similarity threshold of 0.85 (lines 2-70).

When matching markets, the system:

  1. Generates embeddings for the target market title using the embeddings service
  2. Queries the vector database for the top-K nearest neighbors (controlled by semanticSearchTopK)
  3. Computes cosine similarity between vectors
  4. Verifies matches that exceed the threshold using secondary checks (slug comparison or exact outcome mapping)

The matcher returns a verified match object with method: 'semantic' when successful, allowing downstream components to proceed with price analysis.

The Opportunity Indexer

The src/opportunity/index.ts file orchestrates the full arbitrage scanning workflow (lines 79-85). This component:

  • Fetches live market data from all enabled platform connectors
  • Passes the semanticMatching configuration flag to the matcher
  • Supplies the semanticSearchTopK parameter (default 5) to limit vector search scope
  • Feeds matched pairs to the arbitrage planner for edge calculation

According to the source code, the indexer only enables semantic matching automatically when embeddings are available in the runtime environment.

Embeddings Service Provider

Located at src/embeddings/index.ts (lines 2-10), the embeddings service provides the vectorization backend for the entire matching system. The implementation supports multiple providers through a plugin architecture:

  • OpenAI API for high-quality text embeddings
  • Voyage AI for specialized semantic search
  • Local models via transformers.js for offline operation

The service caches generated vectors to ensure repeated arbitrage scans remain performant, reusing embeddings for market titles that have already been processed.

Venue-Arbitrage Planner

Once the Opportunity Matcher validates a semantic pair, src/trading/venue-arbitrage-scanner.ts (lines 8-20) constructs the executable arbitrage plan. This component is venue-agnostic—it receives the matched market IDs and fetches current price quotes from each platform to calculate the percentage edge. The planner determines optimal order sizing and routing (which venue to buy from, which to sell to) based on the verified semantic match.

Step-by-Step Arbitrage Detection Flow

The complete cross-platform arbitrage detection using semantic matching follows this implementation path:

  1. Market Data Aggregation – Connectors pull live order books from enabled platforms (Polymarket, Kalshi, Manifold, etc.)

  2. Outcome Normalization – src/opportunity/outcomes.ts converts platform-specific representations (yes/no, up/down, true/false) into a canonical format

  3. Vector Generation – Each market title/description is sent to the embeddings service (memory.semanticSearch) to produce a dense vector representation

  4. Similarity Search – The matcher queries the vector database for the top-K nearest neighbors based on semanticSearchTopK (default 5) and calculates cosine similarity scores

  5. Threshold Verification – Matches exceeding the 0.85 similarity threshold undergo additional verification to confirm they refer to the same underlying event (comparing slugs or exact outcome mappings)

  6. Edge Calculation – For verified pairs, the bot fetches best bid/ask prices on each venue, computes the percentage spread, and filters by the user-defined minEdge parameter

  7. Plan Execution – The venue-arbitrage planner creates a concrete order-routing plan and hands it to the execution engine

Configuration and Usage

Enabling Semantic Matching

According to src/utils/config.ts, the system exposes several configuration parameters that control cross-platform arbitrage detection:

{
  "opportunityFinder": {
    "semanticMatching": true,
    "semanticSearchTopK": 10,
    "minEdge": 1.5
  },
  "memory": {
    "auto": {
      "semanticSearchTopK": 10
    }
  }
}

Setting semanticMatching: true activates the embedding-based matcher. The semanticSearchTopK parameter controls how many candidate markets are examined per query, balancing recall against latency.

Running the Arbitrage Scanner

The following TypeScript example demonstrates how to invoke the opportunity finder programmatically, following the same path as the /arb chat command:

import { opportunityFinder } from './opportunity';
import { Config } from './utils/config';

// Example config – enable semantic matching and limit to 5 nearest vectors
const cfg: Config = {
  opportunityFinder: {
    semanticMatching: true,
    semanticSearchTopK: 5,
    minEdge: 2,               // % edge required to report
  },
};

async function runScan() {
  // Scan all enabled venues and return any arbitrage pairs
  const results = await opportunityFinder.scan(cfg);
  console.log('Arbitrage opportunities:', results);
}

runScan().catch(console.error);

This script initializes the semantic matching pipeline and returns any verified arbitrage opportunities found across configured platforms.

Direct Market Matching

For testing or custom integrations, you can invoke the semantic matcher directly without running the full scanner:

import { matchMarkets } from './opportunity/matching';
import { getEmbeddings } from './embeddings';

// Suppose we have two market objects from different platforms
const marketA = { title: 'Will Bitcoin break $30k by 2025?', platform: 'polymarket', ... };
const marketB = { title: 'Bitcoin price > $30,000 on 2025‑12‑31?', platform: 'kalshi', ... };

async function demo() {
  const embeddings = await getEmbeddings(); // initialise provider
  const match = await matchMarkets(marketA, [marketB], { embeddings, semanticEnabled: true });
  if (match) {
    console.log('Semantic match found with score', match.score);
  } else {
    console.log('No semantic match');
  }
}
demo();

The matchMarkets function handles vector lookup, similarity scoring, and verification in a single call, returning the match confidence score when successful.

Summary

  • Vector Embeddings Bridge Platforms: CloddsBot uses dense vector representations of market titles in src/opportunity/matching.ts to overcome semantic differences between platform naming conventions.

  • Configurable Similarity Thresholds: The default 0.85 cosine similarity threshold and top-K search parameters (default 5) in src/opportunity/index.ts balance precision with computational efficiency.

  • Multi-Provider Embedding Support: The src/embeddings/index.ts architecture supports OpenAI, Voyage, and local transformers.js models, with built-in caching for performance.

  • Verification Prevents False Positives: Even high-similarity matches undergo secondary verification (slug or outcome comparison) before being passed to src/trading/venue-arbitrage-scanner.ts for price analysis.

  • Unified Command Interface: The /arb skill in src/skills/bundled/arbitrage/index.ts exposes the entire pipeline through a single chat command, using the same configuration structure as the programmatic API.

Frequently Asked Questions

How does CloddsBot handle different naming conventions across platforms?

CloddsBot converts market titles into vector embeddings using the service in src/embeddings/index.ts, which captures semantic meaning rather than relying on exact string matches. This allows the system to recognize that "Will Bitcoin break $30k by 2025?" and "Bitcoin price > $30,000 on 2025‑12‑31?" refer to the same underlying event despite different phrasing, formatting, and date representations.

What similarity threshold indicates a valid semantic match?

According to the source code in src/opportunity/matching.ts, the default cosine similarity threshold is 0.85. Matches exceeding this value are flagged as potential semantic equivalents, though they still undergo secondary verification (comparing market slugs or outcome mappings) before being accepted as valid arbitrage pairs.

Can the arbitrage scanner operate without semantic embeddings?

Yes. The semanticMatching configuration flag in src/opportunity/index.ts allows the system to fall back to plain-text or slug-based comparison methods when embeddings are unavailable or disabled. However, semantic matching significantly improves recall for cross-platform arbitrage detection by identifying paraphrased or differently formatted market titles that exact-match algorithms would miss.

How does the system prevent false positive arbitrage signals?

Even when vector similarity exceeds the 0.85 threshold, the matcher in src/opportunity/matching.ts performs additional verification around line 70 to confirm the markets truly reference the same event. This includes comparing platform-specific identifiers (slugs) and verifying that outcome mappings align correctly. Only after this verification step does the venue-arbitrage scanner calculate price spreads and generate trading plans.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →