Back to Blog
How to Turn Arkham Alerts into Automated Trades
LLM Reaction10 min read

How to Turn Arkham Alerts into Automated Trades

Arkham puts names on wallets. Exchanges, funds, market makers, well-known traders: when one of them moves coins, Arkham can tell you who it was. An Arkham alert fires the moment a transaction matches the filters you set, like "more than $10M of ETH leaving an exchange".

Most people get those alerts by email or Telegram, read them when they get to them, and maybe trade. Arkham can also send every alert to a webhook. Point that webhook at a Data Webhook and a Reaction strategy reads each alert the second it lands and decides whether to trade.

This post builds that pipeline end to end: the alert, the webhook, an AI version and a code version of the reaction, and a way to run it with no money at risk first.

What an Arkham alert gives you

An Arkham alert watches the chain for transactions that match your filters. You can filter on:

  • Entity or address
  • Sending entity and receiving entity
  • Token
  • Token amount
  • USD value
  • Chain

Alerts go out by email, Telegram or webhook, and each one links straight to the transaction on Arkham. Arkham's own example is a good picture of what's possible: every non-stablecoin transfer from FalconX or Galaxy Digital worth more than $10M. Your notification limits and usage sit in a panel at the bottom left of the Alerts page.

The filters on entities are what make this useful for trading. A plain on-chain alert tells you one address sent 8,000 ETH to another. An Arkham alert can tell you a market maker sent it to Binance. You can form a view on the second one.

How the pieces fit

Both Arkham alerts post to one Data Webhook. The Reaction reads each one and sends a signal only when your rules say so. The Bot Webhook logs it, and a Signal Bot places the order once you attach one.

There are two kinds of Reaction, and this post builds both:

  • An LLM Reaction hands each alert to an AI model along with your prompt. It reads the payload as it comes and can weigh who sent what to whom.
  • A Code Reaction runs your JavaScript on each alert. Fixed rules, no model cost, the same answer every time.

Pick one, or run both on separate Bot Webhooks and compare them.

The idea we're testing

Our example watches ETH moving on and off exchanges. The common read goes like this: when big holders pull ETH off exchanges into their own wallets, they plan to hold it. When they send ETH to an exchange, they may be about to sell.

It's a popular read, not a rule. Market makers and OTC desks move coins for plenty of other reasons. So we treat it as an idea to test, not a strategy to fund on day one.

The rules are long only, so they work on a spot bot on any exchange:

  • ETH leaves an exchange for a fund, a whale or a cold wallet: open a long on ETHUSDT
  • ETH arrives at an exchange from one of them: close the long
  • Close anyway at +5%, at −3%, or after 24 hours
  • Ignore anything under $10M, and anything moving between two exchanges

Step 1: Create a Data Webhook

Create a Data Webhook in Sigrex. There's nothing to configure. Copy its URL, which looks like https://hook.sigrex.io/data/<hash>.

Key Protection only accepts requests that carry an X-Key header with your password. If Arkham's webhook settings don't let you add that header, leave Key Protection off and treat the URL like a password: anyone who has it can send data to your reaction.

Step 2: Point two Arkham alerts at it

In Arkham, open Alerts and click New Alert in the sidebar (or Create Alert in the header). Build two alerts. They use the same filters and only the direction changes:

Choose webhook as the delivery and paste the Data Webhook URL into both. One Data Webhook can take both alerts, because the reaction works out the direction from each transfer.

A few things to get right here:

  • Track the same exchanges everywhere. The code version below matches Binance, Coinbase, OKX, Bybit, Kraken and Bitget. If you add one in Arkham, add it there too.
  • $10M is a starting point. Set it too high and nothing fires for days. Set it too low and you burn through your notification limit.
  • "Any" lets exchange-to-exchange moves through. That's fine. The reaction skips them.

Step 3: Read one real alert before you write any logic

Arkham's docs don't publish the JSON its webhooks send, and guessing field names is how a strategy ends up reading nothing. So wait for the first alert to land, then open the Data Webhook's incoming payloads in Sigrex and find where these sit:

  • the sending entity's name
  • the receiving entity's name
  • the USD value
  • the transaction hash

Write each one down as a dot path into the JSON, like from.entity.name (that one's made up, use yours). The code version needs these paths. The AI version doesn't: it reads the alert the way you just did.

Step 4a: Let an AI read each alert

Create an LLM Reaction on the Data Webhook and set it up like this:

  • Model: any model you've connected, plus a fallback
  • Send signal: on
  • Bot Webhook: the test webhook from Step 6
  • Signal symbol: ETHUSDT

Then paste this prompt:

{{val:symbol=ETHUSDT}}
{{val:min_usd=10000000}}
{{val:max_hold_hours=24}}
{{#: Exits: +5% take profit, -3% stop loss, or the hold limit above }}

You trade {{symbol}} on spot, long only, using Arkham on-chain alerts.
Each run gets one payload. It is either an Arkham alert or a timer ping with "type": "tick".

Payload:
{{data}}

Step 1. Manage the open position first.
If a long is open, get the current {{symbol}} price and compare it with the entry price saved in storage.
Close the long if it is up 5% or more, down 3% or more, or has been open longer than {{max_hold_hours}} hours.
If you closed it, stop.

Step 2. If the payload is a timer ping, stop.

Step 3. Read the alert. Find the token, the USD value, the transaction hash, and who sent it to whom (the Arkham entity names).
Skip the alert if any of these is true:
- the token is not ETH, or the USD value is below {{min_usd}}
- both sides are exchanges, or both sides are the same entity
- neither side is an exchange
- the transaction hash is already in storage

Step 4. Decide.
- ETH left an exchange for a fund, a whale or a cold wallet: bullish.
- ETH arrived at an exchange from a fund, a whale or a market maker: bearish.
Before acting on a bullish alert, fetch the last 24 one-hour candles for {{symbol}}. If price already rose more than 3% in that window, treat the alert as priced in and skip it.
- No position and bullish: open a long and save the entry price in storage.
- Long open and bearish: close the long.
- Anything else: do nothing.

Step 5. Keep a log in storage. For every alert you read, add one line: time, from, to, USD value, transaction hash, decision and reason. Keep only the last 50 lines.

{{data}} is the alert exactly as Arkham sent it, so there are no fields to map. The model finds the entity names and the USD value on its own, and it can tell a fund from a market maker by name, which a keyword list can't.

The {{val:}} lines set your numbers once at the top. You don't need to tell the model what position it holds either: with signal sending on, Sigrex adds the last action, when it ran and the current time to every run. For prices, candles, opening, closing and storage, the model uses the tools that come with signal sending.

The log in Step 5 matters more than it looks. When you review the strategy later, every skip comes with its reason.

Step 4b: Or write the rules in code

If you'd rather have rules you can read line by line, build the same idea as a Code Reaction. It gives the same answer every time and costs nothing per run. The trade-off: it only knows the exchange names you list, and it can't judge who's on the other side.

Create a Code Reaction on the Data Webhook with Send signal on, your test Bot Webhook, and ETHUSDT as the symbol. Fill in FIELDS with the paths from Step 3:

// Arkham exchange flows -> ETHUSDT, spot, long only
// Runs on every Arkham transfer and on every heartbeat ping.

// Dot paths to the fields in your Arkham payload (see Step 3).
// Example: "transfer.from.entity.name". List items use numbers: "items.0.usd".
const FIELDS = {
  from: "", // name of the sending entity
  to: "",   // name of the receiving entity
  usd: "",  // USD value of the transfer
  tx: ""    // transaction hash, used to skip repeats
};

const EXCHANGES = ["binance", "coinbase", "okx", "bybit", "kraken", "bitget"];
const MIN_USD = 10000000;               // ignore transfers under $10M
const TAKE_PROFIT = 5;                  // %
const STOP_LOSS = -3;                   // %
const MAX_HOLD_MS = 24 * 60 * 60 * 1000;
const COOLDOWN_MS = 2 * 60 * 60 * 1000; // at least 2h between entries

const pick = (obj, path) =>
  path.split(".").reduce((o, k) => (o == null ? undefined : o[k]), obj);
const isExchange = (name) =>
  EXCHANGES.some((x) => String(name || "").toLowerCase().includes(x));

let payload;
try {
  payload = JSON.parse($.Request.data);
} catch (e) {
  return;
}

const state = (await $.Storage.get()) || { seen: [], entryAt: 0, entryPrice: 0, lastEntryAt: 0 };
const inLong = $.Strategy.lastTrigger?.action === $.Action.LONG;
const price = await $.getExchangeRate($.Exchange.BINANCE, "ethusdt");

// 1. Exit checks run first, on transfers and heartbeats alike
if (inLong && price) {
  const roi = $.Strategy.roi(true, state.entryPrice || $.Strategy.lastTrigger.price, price);
  const tooOld = state.entryAt > 0 && Date.now() - state.entryAt >= MAX_HOLD_MS;
  if (tooOld || (roi !== null && (roi >= TAKE_PROFIT || roi <= STOP_LOSS))) {
    await $.Strategy.action($.Action.EXIT);
    return;
  }
}

// 2. A heartbeat ping only exists to run the checks above
if (payload.type === "tick") return;

// 3. Skip transfers we have already seen
const tx = String(pick(payload, FIELDS.tx) || "");
if (tx && state.seen.includes(tx)) return;
if (tx) {
  state.seen = [...state.seen, tx].slice(-50);
  await $.Storage.set(state);
}

// 4. Keep only big transfers between an exchange and a non-exchange wallet
const usd = Number(pick(payload, FIELDS.usd));
if (!(usd >= MIN_USD)) return;
const fromExchange = isExchange(pick(payload, FIELDS.from));
const toExchange = isExchange(pick(payload, FIELDS.to));
if (fromExchange === toExchange) return;

// 5. ETH leaving an exchange opens a long, ETH arriving at one ends it
if (fromExchange && !inLong && price && Date.now() - state.lastEntryAt >= COOLDOWN_MS) {
  await $.Strategy.action($.Action.LONG, { id: "arkham-" + tx.slice(-10) });
  state.entryAt = Date.now();
  state.entryPrice = price;
  state.lastEntryAt = Date.now();
  await $.Storage.set(state);
} else if (toExchange && inLong) {
  await $.Strategy.action($.Action.EXIT);
}

A few choices worth knowing about:

  • Empty FIELDS means no trades. Until you fill in the paths, every transfer fails the USD check and the reaction does nothing. That's the safe default.
  • Exits come first. Take profit, stop loss and the 24-hour limit get checked on every run, before anything else, so a heartbeat ping (next step) can close a position too.
  • Names match loosely. isExchange lowercases the entity name and looks for each exchange inside it, so a label like "Binance Hot Wallet" counts as Binance.
  • Exchange to exchange is ignored. If both sides are exchanges, or neither is, the transfer says nothing about holders and gets skipped.
  • Repeats are skipped. The last 50 transaction hashes stay in $.Storage, well under its 24 KB limit.
  • One entry per 2 hours at most. A burst of withdrawals in the same hour opens one position, not five.

Step 5: Give the exits a heartbeat

A reaction wakes up when data arrives. If no big ETH moves on or off an exchange for a day, nothing checks the take profit, the stop loss or the 24-hour limit. The fix is a few lines of Code Strategy that sends {"type": "tick"} to the same Data Webhook every 15 minutes:

// Heartbeat: pings the Arkham Data Webhook every 15 minutes,
// so the reaction can check its exits even when no transfer arrives.
// Send signal: off.

const HOOK = "https://hook.sigrex.io/data/your-data-webhook-hash";
const EVERY_MS = 15 * 60 * 1000;

const state = (await $.Storage.get()) || { last: 0 };

if (Date.now() - state.last >= EVERY_MS) {
  await $.Http.post(HOOK, { type: "tick", at: Date.now() });
  state.last = Date.now();
  await $.Storage.set(state);
}

Create it with Send signal off and put your own webhook hash in HOOK. Code Strategies run on market ticks, and the time saved in storage keeps it to one ping per 15 minutes.

Both reactions above treat a tick the same way: check the exits, then stop. If you run the AI version, each tick is one model call, so 96 a day at 15 minutes. Set EVERY_MS to an hour if that's more than you want to spend.

Step 6: Run it with no money at risk first

Create a Bot Webhook and attach no bot to it. Point the reaction's signals there. Every signal gets logged and no order is placed. We walk through this setup in more detail in how to forward test a strategy.

Let it run for a week or two, then check:

  • How many alerts came in, and how many the reaction skipped. Compare the Data Webhook log with the signal log.
  • Whether the longs would have made money after fees. A shadow run doesn't charge any, so subtract them yourself.
  • Whether the exits fired when they should have, including on quiet days when only heartbeats came in.

When the log looks right, attach a CEX Signal Bot on ETHUSDT with a small amount.

Things worth knowing

Labels are Arkham's best estimate. Arkham's own API guide calls attribution probabilistic and confidence-scored. A wrong label turns into a wrong signal, which is one more reason to start small.

Exchanges move coins between their own wallets all the time. Both versions skip transfers between two exchanges or within one entity, but an unlabelled wallet that belongs to an exchange can still slip through.

A deposit isn't always a sale. It can be collateral, an OTC settlement or a market maker topping up inventory. The stop loss and the 24-hour limit are there for those.

Tune the alert, not just the code. An alert that never fires teaches you nothing. One that fires every few minutes eats your Arkham notification limit and, on the AI version, your model budget. Start in between and adjust once you've seen a week of traffic.

Other alerts work the same way. Swap ETH for another token, watch one fund's wallets, or track stablecoins arriving at exchanges. Give each new idea its own Data Webhook and reaction, so every strategy reads one kind of alert.

From alert to order

Arkham does the hard part: it puts names on wallets and watches the chain for you. A Data Webhook and a Reaction turn those alerts from something you read into something that acts, with your rules in front of every order.

The whole setup is one Data Webhook, one Bot Webhook, one Reaction and one Code Strategy, which fits in the free plan. Create a free account and point your first alert at it.

Related posts

Building an Evolving Strategy with Checkpoints and an LLM Coach
LLM Reaction·7 min read

Building an Evolving Strategy with Checkpoints and an LLM Coach

Letting an AI edit a running strategy sounds great until you ask one question: how do you know the new version is better? In August we showed how an LLM Reaction can supervise a Code Strategy and patch it when something breaks. This post takes the same idea further. The AI may now replace the whole trading logic, and a small set of rules keeps that from turning into guesswork. We call the setup Evo. It trades BTCUSDT on paper, and it is built only from parts you already have on Sigrex: one Cod

2026-10-10
Building a News-To-Trade Workflow for Polymarket
LLM Reaction·7 min read

Building a News-To-Trade Workflow for Polymarket

Prediction markets move on information. A market resolves on a specific, checkable question — did the rate cut happen, did the bill pass, did the company hit the number — and every time new information about that question becomes public, there's a brief window before the market price catches up with it. Most of that window closes in minutes. Nobody is checking Polymarket by hand fast enough to consistently catch it. This post walks through a pipeline that does the watching for you: Perigon deli

2026-08-26
Building Self-Improving Strategies with LLM Reactions
LLM Reaction·7 min read

Building Self-Improving Strategies with LLM Reactions

Here's a thing that happens to basically every strategy eventually: it works great for a while, and then it just... doesn't. Maybe the market shifted. Maybe you hardcoded a threshold that made sense in March and stopped making sense in June. Maybe there's a small bug that's been quietly eating trades for two weeks and you only find out when you happen to open the logs. The usual fix is you, checking in, noticing something's off, and going to patch it. Which works, but it doesn't scale past howe

2026-08-10