Cooldown via ctx.state
cooldown via ctx.state
Mirrors runner/src/plugins/05-exampleCooldown
What this teaches
- ctx.state is a per-plugin KV store (get/set/delete/has/keys)
- Default backend is in-memory (lost on restart) — see plugins/index.ts to wire a persistent backend
- A "trade no more than once per N minutes" pattern
New vs exampleSizing
- Plugin remembers its own last-trade timestamp across ticks
import { noop, type StrategyPlugin } from "@automark/runtime-core";
import { Market } from "@automark/sdk/market";
import { minutes } from "@automark/sdk/duration";
const COOLDOWN_MS = minutes(30); // 30 min between trades
export default function createExampleCooldown(): StrategyPlugin {
const vaultId = process.env.VAULT_ID;
if (!vaultId) throw new Error("exampleCooldown: VAULT_ID not set");
return {
name: "exampleCooldown",
vaultId,
triggers: [{ kind: "cron", everySeconds: 60 }],
async decide(ctx) {
if (ctx.vault.isFrozen) return [noop("frozen")];
// `getOrDefault` from ctx.state — saves the `?? 0` boilerplate that
// wraps almost every cooldown/counter read. Returns the fallback only
// when the key is missing or expired (preserves stored 0 and false).
const lastTradeMs = await ctx.state.get<number>("lastTradeMs") ?? 0;
const sinceLast = ctx.now - lastTradeMs;
if (sinceLast < COOLDOWN_MS) {
return [
noop(`cooldown — ${Math.round((COOLDOWN_MS - sinceLast) / 1000)}s left`),
];
}
const btc = await Market.find({
asset: "BTC",
expiryAfterMs: ctx.now + minutes(5),
client: ctx.suiClient,
});
const p = await btc.price();
const quantity = ctx.vault.maxSinglePosition / 4n;
if (quantity === 0n) return [noop("no headroom")];
// NOTE: we set the cooldown BEFORE the action returns. If the tx fails,
// the cooldown still applies — defensive choice. See exampleOnExecuted to
// record state in onExecuted instead (only on success).
await ctx.state.set("lastTradeMs", ctx.now);
return [
{
kind: "vault.mintBinary",
params: {
marketId: btc.id,
strike: btc.strikeAbove(p.forwardRaw, { pctBps: 200 }),
isUp: true,
quantity,
},
},
];
},
};
}
// ctx.state provides an API to handle in-memory data and persist information across ticks
Environment variables
- VAULT_ID