AArtery
On this page

Arbitrage Signal Stream

Artery ships a streaming arbitrage detector: every 5s the system recomputes spreads for every multi-provider event, applies per-provider fees, and pushes a signal whenever the net edge crosses a profitable threshold.

Channel layout

ChannelWhat
artery:stream:event:<universalId>Full spread snapshot every time a leg's mid moves ≥ 0.5¢
artery:stream:arbitrage:<universalId>Only when net edge after fees ≥ 50 bps; emitted on every tick the condition holds

Both channels carry the standard event envelope:

json{
  "type": "event",
  "subscription_id": "uuid",
  "data": {
    "type": "event.arbitrage",
    "marketId": "evt_e8b415bf-...",
    "payload": { /* see below */ },
    "receivedAt": 1714928400000
  }
}

Arbitrage payload

json{
  "universalId": "evt_e8b415bf-be26-4766-9680-998549fe01b1",
  "fetchedAt": "2026-05-09T05:58:05.037Z",
  "buyProvider": "polymarket",
  "buyMarketId": "0xa8aceb0fb04828602057be...",
  "buyMid": 0.0095,
  "sellProvider": "kalshi",
  "sellMarketId": "KXBTCD-26MAY0917-T69999.99",
  "sellMid": 0.030,
  "grossEdge": 0.0205,
  "netEdge": 0.0203,
  "annualizedReturn": 7.41
}
FieldMeaning
buyProvider / buyMidCheapest YES — execute the BUY leg here
sellProvider / sellMidRichest YES — execute the SELL leg here
grossEdgeRaw mid-to-mid difference (sellMid − buyMid)
netEdgeAfter both legs' round-trip taker fees
annualizedReturnnetEdge × 365 — for ranking only, not actual yield

Quickstart

  1. List the universal events you want to watch
    bashTOKEN="art_live_..."
    curl 'https://api.artery.questflow.ai/v1/events?underlying=BTC&min_providers=2' \
      -H "Authorization: Bearer $TOKEN" \
      | jq -r '.events[].universalId'
  2. Subscribe via WebSocket
    jsimport WebSocket from 'ws';
    const TOKEN = process.env.ART_TOKEN;
    const eventIds = [/* from step 1 */];
    const ws = new WebSocket(`wss://api.artery.questflow.ai/v1/stream?token=${TOKEN}`);
     
    ws.on('open', () => {
      const channels = eventIds.flatMap((id) => [
        `artery:stream:arbitrage:${id}`,
        `artery:stream:event:${id}`,
      ]);
      ws.send(JSON.stringify({ type: 'subscribe', channels }));
    });
     
    ws.on('message', (raw) => {
      const m = JSON.parse(raw.toString());
      if (m.type === 'pong') return;
      if (m.data?.type === 'event.arbitrage') {
        const p = m.data.payload;
        console.log(
          `BUY ${p.buyProvider} ${p.buyMarketId} @ ${p.buyMid} → ` +
          `SELL ${p.sellProvider} ${p.sellMarketId} @ ${p.sellMid}  ` +
          `net=${(p.netEdge * 100).toFixed(2)}c`
        );
      }
    });
  3. Tune the threshold

    Default minimum net edge for emission is 50 bps. To see all positive signals (including marginal):

    bashcurl "https://api.artery.questflow.ai/v1/events/<id>/arbitrage" \
      -H "Authorization: Bearer $TOKEN"

    The /arbitrage REST endpoint uses threshold 0 — it surfaces every positive net edge, even if too small to push to the stream.

Fee schedule

The signal engine deducts a conservative round-trip taker fee per provider:

ProviderDefault takerBpsOverride env
Polymarket20ART_FEES_POLYMARKET_TAKER_BPS
Kalshi50ART_FEES_KALSHI_TAKER_BPS
Hyperliquid HIP-414ART_FEES_HYPERLIQUID_HIP4_TAKER_BPS
Hyperliquid Perp14ART_FEES_HYPERLIQUID_PERP_TAKER_BPS
Hyperliquid DEX30ART_FEES_HYPERLIQUID_DEX_TAKER_BPS

Set in your deployment env to tighten or loosen the filter:

bashART_FEES_KALSHI_TAKER_BPS=25 pnpm --filter @artery/api dev

What the signals don't account for

Warning

The net edge is upper-bound — many real-world frictions can erode it:

  • Slippage — if you're moving size, the displayed mid won't fill at that price
  • Funding rate exposure for leveraged positions (HL Perp / HIP-3)
  • Settlement risk — UMA disputes, Kalshi force-majeure clauses
  • Latency — the snapshot was true 5s ago; market may have moved
  • KYC / geo restrictions — can you actually trade on both legs?

Treat these as triggers for further analysis, not "press 'execute' to win".

Settlement consensus tracking

Each universal event also exposes its historical settlement record across providers:

bashcurl "https://api.artery.questflow.ai/v1/events/<id>/settlement" -H "Authorization: Bearer $TOKEN"
json{
  "universalId": "evt_...",
  "records": [
    { "provider": "polymarket", "polarity": "yes", "resolvedAt": "..." },
    { "provider": "kalshi",     "polarity": "yes", "resolvedAt": "..." }
  ],
  "consensusScore": 1.0
}

A consensus score < 1.0 means the linked markets disagreed on resolution — a flashing red indicator that this kind of event has structural settlement risk and any "arbitrage" should be sized accordingly.

See also

Edit this page on GitHubLast updated
Arbitrage Signal Stream · Artery API Docs