Skip to content
Runner · ExamplesLadderrung 02

Fetch a signal from YOUR backend

fetch signal from YOUR backend

Mirrors runner/src/plugins/02-exampleSignal

What this teaches

  • decide() is plain async TypeScript — you can fetch, call APIs, do whatever you need
  • This is the typical "I have a model running somewhere else, the operator just executes its output" pattern

New vs exampleReadState

  • Decision input comes from an external HTTP endpoint, not on-chain data
import type { StrategyPlugin } from "@automark/runtime-core";

interface Signal {
  action: "hold" | "buy" | "sell";
  asset: string;
  confidence: number;
}

export default function createExampleSignal(): StrategyPlugin {

  const vaultId = process.env.VAULT_ID;

  if (!vaultId) throw new Error("exampleSignal: VAULT_ID not set");

  const signalUrl = process.env.SIGNAL_URL ?? "https://your-backend.com/signal";

  return {
    name: "exampleSignal",
    vaultId,
    triggers: [{ kind: "cron", everySeconds: 5 }],

    async decide(ctx) {

      const res = await fetch(signalUrl);

      const signal = (await res.json()) as Signal;

      if (signal.action == 'hold') return [{ kind:'noop', reason: 'hold'}]

      ctx.logger.info("got signal", { signal });

      return [{ kind: "noop", reason: `observing signal=${signal.action}` }];
    },
  };
}

// insights we can take from this example:

// You can connect an external backend to handle more granular decisions in other languages and keep only execution here. Separation between intelligence/quant code and execution.
//

Environment variables

  • VAULT_ID
  • SIGNAL_URL (defaults to a placeholder)