← Plugin catalog
Finance

Keel

Keel Software, Inc. v1.0.0

Hyperliquid strategy builder

Full description ↓

View on ChatGPT ↗

Save this plugin to Following and return to review observed changes. Follow up to 10 plugins free.

Description

From the marketplace listing

Keel turns your ideas into systematic strategies for Hyperliquid crypto perpetual futures (perps). Connect it to ChatGPT, describe a strategy, and ChatGPT builds it from Keel's strategy components, backtests it on real Hyperliquid history with fees and slippage, and explains the results. With Keel in ChatGPT you can: - Build and edit strategies by describing them - Backtest them and compare runs side by side - Start from a verified strategy in the Keel library - Keep notes on strategies and share a result by link - See how the strategies you run in Keel are doing Everything you create stays in your Keel workspace. Nothing is public unless you share it. Keel in ChatGPT is for strategy research and backtesting. It does not place trades, submit orders, move funds or connect wallets — no order executes inside ChatGPT. What it writes is limited to your own Keel workspace: strategy drafts, backtest runs, notes and share links. Running a strategy with real capital is set up and approved by you in the Keel web app, outside ChatGPT. Backtests are simulations on historical data, not predictions or financial advice; trading perpetual futures carries a substantial risk of loss. Keel measures the strategies you design. It does not give investment advice or recommendations, and backtest results do not predict future returns.

Language: English · Automatically detected from descriptions.

What changed

Keel

Oct 27, 2026 · 1 saved observations

Metadata · Oct 27, 2026 · 00:58 UTC · Compared with Oct 24, 2026 · 13:41 UTC

WHAT CHANGED

Package or technical metadata updated

Package or technical metadata updated

Observed in package metadata. These changes alone do not establish a new customer-facing feature.

Open full comparison.

Is v2 template

Before

Oct 24, 2026 · 13:41 UTC

Not present

After

Oct 27, 2026 · 00:58 UTC

false

Metadata: full comparison →

Competitor profile

From the developer’s listing and package; capabilities are not independently tested. Package observed Nov 2, 2026.

Declared capabilities

Hyperliquid strategy builder

Declared limitations

Specific limitations have not been established. Missing information does not mean unrestricted capabilities.

Cost & access

Pricing and account requirements have not been established from the available package declarations. Unknown pricing does not mean free access.

Starter prompt

Build a momentum strategy across the top 20 Hyperliquid perps and backtest it

View package source →

Files & skills

File archives

Plugin package12 files · 55.7 KBBrowse files →
Skill instructions
backtest-and-analyze6.13 KB

View saved version →

---
name: backtest-and-analyze
description: |
  Run a backtest on an existing strategy and read it: confirm the strategy, run on the strategy's default window unless the user named one, watch to terminal, present the run's view, and interpret the mechanism behind the result. Use when the user says "run a backtest", "test this", "how does it perform", "what's the Sharpe", or names a strategy and asks about performance. Not for robustness checks (overfit-check) or for editing the strategy.
references:
  - step: 2
    topic: "tool_usage"
    why: "backtest mechanics: one continuous simulation, half-open window, warm-up; never N short runs as a substitute for post-processing"
  - step: 2
    topic: "platform_operations"
    why: "the backtest window rule (the default window per timeframe, warm-up, the data floor) and per-asset data coverage"
  - step: 2
    topic: "backtest_costs"
    why: "backtest cost assumptions: the default fee and slippage model every run applies"
  - step: 4
    topic: "trading_domain"
    why: "timeframe facts (too few trades on a short bar), trend vs mean-reversion behaviour, the complexity ladder"
  - step: 4
    topic: "mistakes"
    why: "structural mistakes behind a zero-trade or wrong-direction result"
tools:
  - keel_strategy_search
  - keel_strategy_notes_read
  - keel_backtest_run
  - keel_backtest_watch
  - keel_backtest_summarize
  - keel_backtest_compare
  - keel_strategy_history
  - keel_strategy_notes_add
---

# References

Reference topics this workflow cites (keel_help topics):

- Step 2 — `tool_usage` — backtest mechanics: one continuous simulation, half-open window, warm-up; never N short runs as a substitute for post-processing
- Step 2 — `platform_operations` — the backtest window rule (the default window per timeframe, warm-up, the data floor) and per-asset data coverage
- Step 2 — `backtest_costs` — backtest cost assumptions: the default fee and slippage model every run applies
- Step 4 — `trading_domain` — timeframe facts (too few trades on a short bar), trend vs mean-reversion behaviour, the complexity ladder
- Step 4 — `mistakes` — structural mistakes behind a zero-trade or wrong-direction result

# Method

## Step 1 — Confirm inputs and read prior context

- A `strategy_id` from the user, else `keel_strategy_search(limit=5)` and
  confirm which one.
- `keel_strategy_notes_read(strategy_id=<id>)` — prior runs and notes may already
  answer the question or say what to look at.
- Window: omit `start_date` / `end_date` unless the user named a period; the
  tool applies the strategy clock's default window and the receipt names the
  window it used.
- More than one run planned (a grid, several windows)? Each run uses one
  backtest of the plan's weekly allowance; say how many runs the batch needs
  before starting, and let the user scope it.

## Step 2 — Run and wait

`keel_backtest_run(strategy_id=<id>, ...)`. The receipt carries `run_id`,
`hero_url`, and usually `summary_metrics`. If the run is still active, or
metrics are absent, `keel_backtest_watch(backtest_id=<run_id>)` — not an ad hoc
polling loop. Once terminal, show the run with `keel_backtest_summarize` if it
is the run you present; for several runs, `keel_backtest_compare` once with
every id. Backtests run the platform's current version; pin a historical one
with `commit_id=...` (from `keel_strategy_history`) only when that is what the user
wants. A run may not finish in the turn: say it started and how to read it;
never promise to report back on your own.

## Step 3 — Read the result

The `view` is the metrics table — where the host draws it the user already
sees it; elsewhere its markdown stands in. Then, in prose: the date range
(always — comparisons across ranges are meaningless), the top-3 / bottom-3
contributors (a Sharpe carried by one asset is a different result from one
spread across thirty), best and worst month. `Sharpe > 3.0` or `Total Return >
500%` on a long window is unusual for a real edge; say so plainly —
`overfit-check` is the robustness check for a result like that.

## Step 4 — Reason about it

Three bullets: did the thesis work as designed or for another reason; where
did it underperform and is that consistent with the strategy type (trend
bleeds in chop); what would a principled next iteration change — a mechanism
fix with a reason independent of the backtest, never a change designed to
dodge one bad period. Diagnose the mechanism, not the outcome: "mean-reversion
shorts in a parabolic breakout with no trend filter" is a mechanism; "shorts
lost money in Nov 2024" is an outcome. Report the result first, then the
caveats.

## Step 5 — Save a note when asked

When the user asks to save or remember the result,
`keel_strategy_notes_add(strategy_id=<id>, note=<one paragraph>)`: Sharpe,
return, max DD, window, one-line interpretation. End the reply with the
`hero_url` on its own line.

# Decision points

- One run → summarize; several → compare once. Never both for the same run.
- Plan-limit refusals (`quota_exhausted`, `quota_cap_reached`,
  `plan_feature_unavailable`) carry the numbers: report the limit and the
  reset. The call is not retried; re-authenticating adds no capacity.
- Simulation framing (daily reset, withdrawals, "add $X a week") is not a
  reason for N short backtests: run one over the full window and decompose
  from trades and equity.

# Output shape

1. One sentence: strategy, Sharpe, return, max DD, window.
2. The run's `view` — explained, not repeated, where the host draws it.
3. Top-3 / bottom-3 contributors.
4. Three bullets of "what this means".
5. `hero_url` on its own line.
6. Where a follow-up is natural, one line naming it — a robustness check
   (`overfit-check`) for an unusually strong result, a mechanism fix
   (`strategy-fork-and-iterate`) for a clear weakness — for the user to pick.

# When NOT to use

- Robustness / out-of-sample → `overfit-check`.
- Comparing runs → `keel_backtest_compare`.
- Creating or editing the strategy first → `strategy-creation` /
  `strategy-fork-and-iterate`.

# Test prompts

1. "Run a backtest on str_K9p2Lz from <start> to today."
2. "What's the Sharpe of my funding carry strategy?"
3. "Test the strategy I just created."
component-discovery4.24 KB

View saved version →

---
name: component-discovery
description: |
  Find the Keel component(s) that implement a concept the user names: search by concept, batch the candidates' schemas, show what precedes and follows the best one. Use when the user asks "what component does X", "is there a way to Z", "find a component for Y", or names a trading concept and wants what implements it. Not for composing a strategy (strategy-creation) or for one already-named component (keel_components_get).
references:
  - step: 2
    topic: "types"
    why: "the type universe, when a filtered typed search proves absence (reference/)"
  - step: 4
    topic: "composition_mechanics"
    why: "how the candidate wires: slot-reading components, Parallel partners, the two mask systems"
  - step: 4
    topic: "slots"
    why: "slot reads/writes semantics for a slot-reading candidate (reference/)"
  - step: 4
    topic: "strategy_patterns"
    why: "the pattern a candidate usually lives in"
tools:
  - keel_components_search
  - keel_components_get_many
  - keel_components_get
---

# References

Reference topics this workflow cites (keel_help topics):

- Step 2 — `types` — the type universe, when a filtered typed search proves absence (reference/)
- Step 4 — `composition_mechanics` — how the candidate wires: slot-reading components, Parallel partners, the two mask systems
- Step 4 — `slots` — slot reads/writes semantics for a slot-reading candidate (reference/)
- Step 4 — `strategy_patterns` — the pattern a candidate usually lives in

# Method

## Step 1 — Translate words into a concept

"Beta hedge", "trailing stop", "regime detection", "Kalman filter" — search
for the concept, not the literal word; the search is semantic and the catalog
holds names (`BetaHedgeAllocator`, `TrailingStopExit`, `FundingLevelRegime`)
that no pattern doc lists. A name from another platform is translated to the
Keel concept first.

## Step 2 — `keel_components_search`

Query the concept; narrow with `category`, `input_type` / `output_type`
(a filtered typed search is exhaustive — an empty one is the evidence for "no
component does X"; a thin keyword search is not), or `clock_direction`.
Surface the top 3–5, ranked, with one line each. Nothing fits → say "the
closest is X but it does not cover Y"; never fabricate a fit.

## Step 3 — Batch the candidates

`keel_components_get_many(names=[...])` once for the 3–5 candidates: full
params, types, slot reads/writes, examples, pitfalls, version — compared side
by side. A single component the user already named →
`keel_components_get(name=<name>)` is cheaper. Note when a locked version
differs from the latest; changing a pinned version is the user's call.

## Step 4 — Show how it wires

`keel_components_search(after=<name>)` lists what can follow the candidate;
`(before=<name>)` what can precede it. A component alone is half the answer —
what feeds it and what consumes it is the other half. For a slot-reading
candidate (`entry_slot`, `ohlcv_slot`), say which earlier `Store` it needs.

## Step 5 — Where discovery ends

This workflow ends at discovery. Building a new strategy with the component is
the `strategy-creation` workflow; adding it to an existing one is
`strategy-fork-and-iterate`.

# Decision points

- Universe / asset-filter questions are discovery like any other; there is no
  separate universe skill.
- The catalog is the truth, not training data: a component you have not seen
  in a result this session is not asserted to exist — or not to.

# Output shape

1. One-sentence interpretation of the concept.
2. Top 3–5 candidates: name × one line × category.
3. For the leading candidate: param highlights and 1–2 example usages.
4. What precedes and follows it.
5. If the user wants to build with it: `strategy-creation` (new strategy) or
   `strategy-fork-and-iterate` (existing strategy).

# When NOT to use

- Building a strategy → `strategy-creation`.
- One named component → `keel_components_get` (or
  `keel://components/<name>/schema` where the host browses resources).
- A failing strategy → `recover-from-error`; discovery fixes no validation
  error.

# Test prompts

1. "Is there a component for beta hedging in Keel?"
2. "How do I add a trailing stop to my strategy?"
3. "What components handle regime detection on funding rates?"
overfit-check4.7 KB

View saved version →

---
name: overfit-check
description: |
  Probe whether a backtest result is robust or curve-fit: re-run the strategy on disjoint windows and regimes the user agrees to, optionally perturb the sensitive parameters, compare the runs once, and give one verdict (ROBUST / MIXED / OVERFIT). Use when the user asks "is this real?", "is this overfit?", "out-of-sample", "walk-forward", or asks for a robustness check; the check is most informative on an unusually strong in-sample result (Sharpe above 3.0, return above 500%). Not a substitute for the first backtest (backtest-and-analyze).
references:
  - step: 2
    topic: "platform_operations"
    why: "the backtest window rule: warm-up and the data floor for each probe window"
  - step: 3
    topic: "trading_domain"
    why: "complexity ladder (>25 free parameters is overfitting), which parameters are the sensitive ones"
  - step: 4
    topic: "reasoning_principles"
    why: "each transform once; signal diversity over parameter variants when reading a fragile result"
tools:
  - keel_backtest_run
  - keel_backtest_watch
  - keel_backtest_compare
---

# References

Reference topics this workflow cites (keel_help topics):

- Step 2 — `platform_operations` — the backtest window rule: warm-up and the data floor for each probe window
- Step 3 — `trading_domain` — complexity ladder (>25 free parameters is overfitting), which parameters are the sensitive ones
- Step 4 — `reasoning_principles` — each transform once; signal diversity over parameter variants when reading a fragile result

# Method

## Step 1 — Confirm the baseline

The `strategy_id`, the baseline `run_id` (or run one on the default window),
and its window. State the baseline Sharpe / return / max DD before probing.

## Step 2 — Agree the out-of-sample windows

The probe takes several runs — one backtest of the plan's weekly allowance
each, plus wall-clock time. Before starting, say how many runs it needs and
which windows, and start once the user agrees; they may drop or pick
windows. Windows the user named are used as given. When the user asks for a
default split, this one is relative to the baseline window:

- W1 in-sample — its first half;
- W2 out-of-sample — its second half;
- W3 held-out tail — the most recent 3 months;
- W4 / W5 regimes — one high-vol stretch, one low-vol / chop stretch.

Every window must cover the strategy's warm-up. For each agreed window:
`keel_backtest_run(strategy_id=<id>, start_date=<start>, end_date=<end>)`; if still active,
`keel_backtest_watch(backtest_id=<run_id>)`. When all are terminal,
`keel_backtest_compare` once with every window's id — the table is the
comparison view.

## Step 3 — Parameter perturbation (only when the user asks for depth)

Pick the 1–2 parameters that matter (a lookback, a threshold, a leverage
cap — not a seed). Perturb ±20% and ±50% — four runs per parameter, stated
before starting — and compare once. A Sharpe that collapses under ±20% points
to a fitted parameter rather than an edge.

## Step 4 — Read stability

- Sharpe spread across windows: max − min > 2.0 with any window negative is
  fragile. Real edges degrade smoothly.
- Sign of returns: one negative disjoint window is a yellow flag; two are red.
- Parameter sensitivity: robust to ±20% or it is not an edge.

## Step 5 — Verdict

- **ROBUST** — stable Sharpe, positive across regimes, parameters not
  razor-thin.
- **MIXED** — some windows weak, thesis holds in most; a candidate for
  further out-of-sample testing.
- **OVERFIT** — variance too high, negative OOS, or razor-thin parameters.

One sentence, then the windows / perturbations that drove it.

# Decision points

- Disjoint is not cherry-picked: never place the OOS window on a known good
  period.
- An average across windows hides a −3.0 window; read every row.
- A ROBUST verdict is necessary, not sufficient — it describes historical
  windows only.
- A fragile result is answered with robustness, not with less exposure: a
  trend filter, sizing, or a regime gate, rather than removing exposure to
  dodge one bad window — that is curve-fitting.

# Output shape

1. The verdict sentence.
2. The comparison `view` (all windows) — explained, not repeated, where the
   host draws it.
3. The perturbation comparison, if run.
4. Two bullets of interpretation.
5. What the verdict implies: further out-of-sample testing / iterate further
   / discard.

# When NOT to use

- First-pass backtest → `backtest-and-analyze`; a strategy one run shows is
  broken gains nothing from five more.
- Authoring or editing → the creation or fork skills.

# Test prompts

1. "Is this 3.5 Sharpe real, or am I overfitting?"
2. "Run an out-of-sample check on str_K9p2Lz."
3. "Walk-forward this strategy across the last year."
portfolio-review3.97 KB

View saved version →

---
name: portfolio-review
description: |
  Summarise the strategies running on the user's account, read-only: positions, recent fills, drawdown against backtest expectations, and anything errored or stale. It changes nothing; starting or stopping a strategy happens in the Keel web app. Use when the user asks "how are my strategies doing", "what's running", "portfolio status", or asks about several running strategies at once. Not for backtesting a candidate (backtest-and-analyze).
references:
  - step: 2
    topic: "capability_boundaries"
    why: "per-series freshness and bar-close semantics — what a recorded view can and cannot state"
  - step: 3
    topic: "trading_domain"
    why: "leverage caps; why Sharpe over a short sample is noise"
tools:
  - keel_live_monitor
  - keel_app_link
---

# References

Reference topics this workflow cites (keel_help topics):

- Step 2 — `capability_boundaries` — per-series freshness and bar-close semantics — what a recorded view can and cannot state
- Step 3 — `trading_domain` — leverage caps; why Sharpe over a short sample is noise

# Method

Every call here reads; none changes a running strategy.

## Step 1 — Enumerate

`keel_live_monitor(view="portfolio")` with no `deployment_id` — the summary
across every running strategy (and account, unless the user named one). Read
the `freshness` block first: the portfolio view is recorded backend state and
can lag the web dashboard.

## Step 2 — Read each strategy the user cares about

- **Positions** — `keel_live_monitor(deployment_id=<id>, view="positions")`,
  an on-demand exchange snapshot of what one strategy holds now. For several
  strategies, say when you only have the recorded summary.
- **Recent fills** — the `trades` view for one strategy, with `limit=20`.
- **Drawdown** — `view="equity"` or `view="stats"` for one strategy; set its
  realized drawdown beside the drawdown its backtest showed.
- **Totals** — account value, realized and unrealized P&L (both, always),
  funding, fees, running and total strategy counts, from the portfolio view's
  fields. Do not invent day / week / MTD returns from the summary; fetch a
  specific view only if asked.

## Step 3 — Flag what needs attention, first

- Errored orders or executions in the last 24 h
  (`view="executions"`, `limit=5`).
- Realized drawdown beyond the backtest's drawdown.
- No rebalance in more than 2× the target interval (stale).
- Net leverage above the user's stated risk preference (ask if unknown).

Errors before metrics — never inside a metrics wall.

## Step 4 — Report the data

Show the data and name what it shows; recommend nothing unprompted. A
question about starting, stopping or changing a strategy is answered with the
evidence; the change itself happens in the Keel web app, and
`keel_app_link` returns the page.

# Decision points

- A running strategy's Sharpe against its backtest Sharpe needs a sample:
  under ~60 trading days it is noise — say so instead of comparing.
- "My main account" means filter to it; do not roll everything up.
- Unrealized is not realized; print both, the difference is real.

# Output shape

1. One-sentence summary of what is running ("4 strategies running on
   1 account; one has an errored order in the last 24 h").
2. Totals from the portfolio view's fields.
3. Per-strategy table: name × realized P&L × age × status.
4. Flagged items, if any.
5. Top-3 positions only if fetched from `positions`; otherwise say not fetched.
6. `hero_url` for the portfolio dashboard.

# When NOT to use

- Starting, stopping or changing a running strategy → the user does that in
  the Keel web app (`keel_app_link`).
- One strategy in depth → `keel_live_monitor(deployment_id,
view="overview")` and its read-only views; `recover-from-error` if the tools
  themselves keep failing.
- A candidate replacement → `backtest-and-analyze`.

# Test prompts

1. "How are my strategies doing?"
2. "Give me a status across everything that's running."
3. "What's running right now, and has anything errored?"
recover-from-error4.97 KB

View saved version →

---
name: recover-from-error
description: |
  Triage repeated keel_* tool failures: capture the errors, read keel_account_status and keel_connection_check, classify by the error's code (auth, scope, quota, sync, validation rule, handoff), and propose one specific next step. Use when the user says "this keeps failing", "what's wrong", "debug this", or pastes an error. Not for a single failure — the originating tool's error already says what to do.
references:
  - step: 4
    topic: "rule:<CODE>"
    why: "the lesson behind a validation issue code"
  - step: 4
    topic: "mistakes"
    why: "structural mistakes that validate but do not work (zero trades, wrong polarity)"
  - step: 4
    topic: "universe_selection"
    why: "Universe selectors and resolved semantics behind EMPTY_UNIVERSE / unknown-symbol errors"
tools:
  - keel_account_status
  - keel_connection_check
  - keel_help
  - keel_feedback
---

# References

Reference topics this workflow cites (keel_help topics):

- Step 4 — `rule:<CODE>` — the lesson behind a validation issue code
- Step 4 — `mistakes` — structural mistakes that validate but do not work (zero trades, wrong polarity)
- Step 4 — `universe_selection` — Universe selectors and resolved semantics behind EMPTY_UNIVERSE / unknown-symbol errors

# Method

## Step 1 — Capture the last three errors

From the tool history: tool names, the `code` (envelope code or validation
issue code), the `message`, and the arguments. Fresh session and nothing
visible → ask the user to paste the most recent error verbatim.

## Step 2 — `keel_account_status`

Auth state and identity, API URL, the toolsets and tools visible right now,
remaining plan quota, cross-surface hints. Most "keeps failing" sessions are
one of: not authenticated, a tool outside the active toolsets, the wrong
account context, or an exhausted quota — all visible here.

## Step 3 — `keel_connection_check` when status looks clean

One read-only pass over auth, API reachability, and the active tool surface;
it exits non-zero on any failed check. Quote what it names in prose, not raw
JSON.

## Step 4 — Classify by code and apply the documented fix

- **Validation issue code** (`TYPE_MISMATCH`, `UNKNOWN_COMPONENT`,
  `SLOT_REF_NOT_FOUND`, `LOADER_TIMEFRAME_UNBOUND`, …) →
  `keel_help(topic="rule:<CODE>")` for the lesson; the issue's `suggestion`
  and `location` say what and where. `UNKNOWN_COMPONENT` is a search-then-edit,
  never a delete.
- **A strategy that validates but trades zero / the wrong way** → the
  `mistakes` reference (binary signals re-normalized, polarity, sizer before
  PSM).
- **401 / 403, `authenticated: false`** → sign in again through whatever
  connected you: on the hosted endpoint, the client's own connect / reconnect.
- **A plan-limit refusal** (`quota_exhausted`, `quota_cap_reached`,
  `plan_feature_unavailable`) → the refusal carries `limit_details` (the unit,
  and for a quota the used, limit and reset numbers) and `resume.verify_call`
  (the exact blocked call, every argument kept). Report the limit and the reset
  in words; a plan-limit refusal is not retried; it lifts at the reset.
- **`handoff_required`** is not an error: it names a step the user completes
  in the Keel web app.
- **`not_found` on a help topic / skill** → the error lists the closest names.

## Step 5 — One specific next step

Not a list of things to try. "The error points at <X>. Try <one call>. If it
still fails, paste the new error." The same call with the same arguments is
not a next step; if the previous call failed with those, they are the problem.

## Step 6 — Do not loop

If the same failure survives a second pass through this workflow in one
session, the loop is not converging: say so and stop retrying. When the user
wants it reported, `keel_feedback` files the report from inside the session —
show them what it will carry first (the exact prompt or command, the error
verbatim, and `keel_connection_check`'s output) and send it once they agree.
Credential or private-account matters go to `https://usekeel.io/contact`, not
into a report.

# Decision points

- Quote the original error verbatim so the user knows you read it; the
  diagnosis names the field or output that led to it.
- A tool you are unsure exists is tried, not declared missing.

# Output shape

1. One-sentence diagnosis ("Your session is not authenticated — sign in
   again").
2. The evidence (which call's output, which field).
3. The single recommended next call or action.
4. Optional: the `rule:<CODE>` or mistake reference.

# When NOT to use

- A first failure with the user not yet stuck → the originating tool's error
  says what to do.
- A "how do I" question → the relevant skill.
- A strategy-logic problem (validates, runs, loses) → `backtest-and-analyze`
  or `overfit-check`; this skill diagnoses tool friction, not edges.

# Test prompts

1. "This keeps failing — same error every time."
2. "I can't get past this 422 on strategy compose, here's the trace ..."
3. "Why does every backtest call return 401?"
strategy-creation14.2 KB

View saved version →

---
name: strategy-creation
description: |
  Author a new Keel strategy from a natural-language thesis: fix path, universe and polarity; search every concept; batch-verify component types; draft the declarations and one Pipeline; dry-run until clean; save; and, when the user wants one, backtest and read the result. Use when the user says "create / build / make me a strategy", "new strategy that ...", or describes a trading idea and wants it implemented. Not for editing an existing strategy (strategy-fork-and-iterate) or for looking up one component (component-discovery).
references:
  - step: 1
    topic: "strategy_paths"
    why: "Path 1–4 chains, PSM vs ScalingPositionManager and when each applies, Path-2 direction and exits (the sizer table is in trading_domain)"
  - step: 1
    topic: "strategy_patterns"
    why: "pattern snippets when the thesis names one: entry/exit, screen-select, pairs, beta hedge, DCA, regime"
  - step: 1
    topic: "trading_domain"
    why: "the timeframe floor and the per-strategy timeframe table, carry and oscillator polarity, required component pairs, complexity ladder, the entry/exit sizer table"
  - step: 1
    topic: "pipeline_system"
    why: "the type progression OHLCVDict → SignalSeries → … → WeightSeries"
  - step: 3
    topic: "reasoning_principles"
    why: "the invariants to check on the mock: terminal WeightSeries, normalize only when needed, each transform once, path matches signal type, a discrete strategy needs a way out, universe before signal"
  - step: 4
    topic: "dsl_syntax"
    why: "the declarations with one example; the Execution mode for each path; Parallel / Store / Load / variable / factory syntax"
  - step: 4
    topic: "composition_mechanics"
    why: "Parallel semantics and branch isolation, the two mask systems, slot-reading components, loaders following Globals vs an own-clock branch"
  - step: 4
    topic: "universe_selection"
    why: "Universe selectors, manual vs criteria modes, resolved semantics, groups — when the user names an asset scope"
  - step: 4
    topic: "data_loading"
    why: "validated examples of every loader/clock shape — carry, own-clock smoothing, accrual, projection, two price clocks"
  - step: 5
    topic: "rule:<CODE>"
    why: "the lesson behind any validation issue code the dry run returns"
  - step: 5
    topic: "mistakes"
    why: "the structural mistakes by id — most now carry a validator code with its own fix; the few with none are checked by eye"
  - step: 5
    topic: "tool_usage"
    why: "pipeline completeness: a backtest refuses a pipeline that does not end in weights, and names the missing step"
tools:
  - keel_components_search
  - keel_components_get_many
  - keel_components_get
  - keel_strategy_compose
  - keel_backtest_run
  - keel_backtest_summarize
  - keel_backtest_compare
  - keel_strategy_readiness
---

# References

Reference topics this workflow cites (keel_help topics):

- Step 1 — `strategy_paths` — Path 1–4 chains, PSM vs ScalingPositionManager and when each applies, Path-2 direction and exits (the sizer table is in trading_domain)
- Step 1 — `strategy_patterns` — pattern snippets when the thesis names one: entry/exit, screen-select, pairs, beta hedge, DCA, regime
- Step 1 — `trading_domain` — the timeframe floor and the per-strategy timeframe table, carry and oscillator polarity, required component pairs, complexity ladder, the entry/exit sizer table
- Step 1 — `pipeline_system` — the type progression OHLCVDict → SignalSeries → … → WeightSeries
- Step 3 — `reasoning_principles` — the invariants to check on the mock: terminal WeightSeries, normalize only when needed, each transform once, path matches signal type, a discrete strategy needs a way out, universe before signal
- Step 4 — `dsl_syntax` — the declarations with one example; the Execution mode for each path; Parallel / Store / Load / variable / factory syntax
- Step 4 — `composition_mechanics` — Parallel semantics and branch isolation, the two mask systems, slot-reading components, loaders following Globals vs an own-clock branch
- Step 4 — `universe_selection` — Universe selectors, manual vs criteria modes, resolved semantics, groups — when the user names an asset scope
- Step 4 — `data_loading` — validated examples of every loader/clock shape — carry, own-clock smoothing, accrual, projection, two price clocks
- Step 5 — `rule:<CODE>` — the lesson behind any validation issue code the dry run returns
- Step 5 — `mistakes` — the structural mistakes by id — most now carry a validator code with its own fix; the few with none are checked by eye
- Step 5 — `tool_usage` — pipeline completeness: a backtest refuses a pipeline that does not end in weights, and names the missing step

# Method

The whole construction, in order: read the thesis → name its concepts →
discover the components → mock the typed chain → draft from the skeleton →
dry-run, reading each issue's fix → save → backtest when the user wants one
→ read the result and reason about why.

## Step 1 — Read the thesis; settle three decisions before any tool call

1. **Path.** Continuous forecast (Path 1), discrete entry/exit (Path 2),
   screen-select (Path 3), direct allocation (Path 4). "buy when / sell when /
   entry / exit / crosses" → discrete; "rank / weight / tilt / score /
   forecast" → continuous. Architecture ambiguity → ask ONE question.
2. **Universe — choose the asset set.** Assets the user named →
   `Universe(mode="manual", symbols=[...])`. A scope they described (liquid
   majors, a sector) → a criteria universe: `Universe(mode="top_volume",
top_n=30, market="perp")`, the convention, or `mode="category"`. No hint
   of scope at all → ask which assets, offering the top_volume convention.
   Never write `resolved=`; the save resolves criteria and bakes the list.
   "HL perps" is `market="perp"`. Nothing injects a Universe: without one the
   strategy fails validation (`MISSING_UNIVERSE`).
3. **Polarity.** Trend-following unless the user says fade / overbought /
   oversold / reversal / contrarian / mean reversion.

Clock: `1d` unless the user names one. An unsupported timeframe is offered as
the nearest supported value and changed only with consent — never silently.

Match complexity to specificity: vague → one question, then the simplest
viable version; detailed ("EWMAC 2/8 with FDM and vol sizing") → exactly as
stated, nothing simplified.

## Step 2 — Search every concept

For each building block (data, signal, entry, exit, filter, sizing) and every
concept the user names ("beta hedge", "trailing stop", "vol targeting",
"regime"): `keel_components_search(query=<concept>)`. Search even when you know
the indicator's name — the result gives the canonical name, its output type,
and any adapter it needs (a raw indicator value wants `ThresholdCross` before
an entry slot). A concept with no clean match is said out loud, not
approximated silently; a hand-rolled substitute (a `ConstantForecast(-10)` for
a beta hedge) is a different strategy from the one asked for.

## Step 3 — Mock the graph, then batch-verify

Write the chain as names with the type you expect at each arrow (no DSL yet):

```
PriceDataLoader → OHLCVDict · ROC → SignalSeries · CrossSectionalZScore → NormalizedSignal
· ForecastScaler → ForecastSeries · ForecastCapper → ForecastSeries · ForecastWeightNormalizer → WeightSeries
```

Then ONE `keel_components_get_many(names=[...])` over every name,
standard components (`PriceDataLoader`, `Store`) included. Walk it pair-wise:
output type = next input type? required params covered? does a component
read a slot that needs an earlier `Store`? did search surface a better
candidate you did not mock? A type gap means search for a bridging component
or swap the pick — never force it. Only after the batch fits do you write
DSL: a wrong shape costs one batch call here and a compile round-trip plus a
redraft after.

Multi-signal joins: one directional signal + the other as a filter through
`ApplyMask`; `MaskAnd`/`MaskOr` are for exits and boolean filters (they lose
direction). Independent branches → a `Parallel` dict, not serial Store/Load;
each branch sizes to WeightSeries before `WeightConcatenator`, and the book's
gross exposure is the sum of the branch targets — split the target across
branches or cap after with `LeverageCap`.

## Step 4 — Draft from the skeleton

The declarations, then exactly one `Pipeline(...)` — the skeleton
`keel_strategy_compose`'s description carries:

```
Globals(target_timeframe='1d')
Universe(mode='top_volume', top_n=30, market='perp')
Execution(rebalance='buffered', buffer_threshold=0.2, buffer_mode='relative', rebalance_method='to_edge')
Pipeline([
    PriceDataLoader(),
    ROC(period=20),
    ForecastScaler(avg_abs_target=10.0),
    ForecastCapper(limit=20.0),
    ForecastWeightNormalizer(target_leverage=1.0),
], name='my_strategy')
```

`Globals(target_timeframe, bar_offset)` is the only place the clock lives.
`bar_offset` is omitted unless the user asks for a different close: omitted,
bars close on the timeframe's own boundary (00:00 UTC for `1d`). An offset
moves every bar and so changes every signal and result — `'12h'` closes the
daily bar at 12:00 UTC, and one daily strategy measured −7.1% with it against
+44.6% without; the reply says so when one is declared. `Universe(...)` is
required. `Execution(rebalance=...)`: `buffered` for Path 1 (continuous weights),
`on_change` for Paths 2 and 3 (binary weights), `every_bar` only for a
constant-weight basket. The pipeline ends in a
normalizer or sizer producing WeightSeries. No imports; component names
bare; keyword arguments only. A bare loader follows Globals with no resampler
after it; an explicit `timeframe=` on a loader is a branch on its own clock
and comes back through `TargetSignalResampler` (finer) or
`TargetSignalProjector` (coarser). A Parallel dict is consumed by a composer
or `Extract`. Add what the user asked for plus the required glue, one
sentence per addition.

## Step 5 — Dry run until clean

The most important step. `keel_strategy_compose(dry_run=True, source=...)`.
Every issue carries a `code`, a `message` and a `suggestion` — the fix. Read
the code first; `keel_help(topic="rule:<CODE>")` explains it. A parse failure
comes back the same way (its own code, the fix and the span), so an import
line or a positional argument costs one round trip, not a guess. Apply the
fix, re-run. A save does not wait for a clean validation — only parse and
compile errors block it, and a backtest run refuses a pipeline that is not
backtest-ready — so clean is the dry run's job: no error-severity issue
outstanding before the save; warnings are read and either fixed or explained
to the user. The few structural mistakes no validator code catches yet are in
the `mistakes` reference; check those by eye. Read the returned `universe`
block (mode, resolved count, preview) before moving on.

## Step 6 — Save

`keel_strategy_compose(source=..., name=<descriptive_snake_case>,
description=<the thesis in the user's words>)`. Where the host draws the
result's card the user already sees it — explain it in your own words;
elsewhere its markdown stands in. When the user asks where the strategy
stands, `keel_strategy_readiness(strategy_id=<id>)` reports its evidence; its
`next_recommended_action` is a field of that report, not an instruction.
Further edits are the `strategy-fork-and-iterate` workflow.

## Step 7 — Backtest when the user wants one, then reason about the result

A backtest uses one run of the plan's weekly allowance: run it when the user
asked how the strategy performs, or agrees to a run.
`keel_backtest_run(strategy_id=<id>)` with no dates runs the strategy clock's
default window and cost model; pass a window only when the user named one.
`keel_backtest_summarize` shows one finished run, `keel_backtest_compare`
several variants in one call. Then read it and reason WHY — the mechanism, not the outcome: which exposure produced
the return, whether the costs, the carry or one window explain it, and how it
compares with the BTC hold reference over the same span. Prefer a principled
fix over curve-fitting one bad window; the next change is one small edit
(`strategy-fork-and-iterate`), saved as a new version of this strategy.

# Decision points

- Ask vs proceed: architecture ambiguity (trend vs MR, continuous vs discrete)
  → one question; a parameter or minor choice → proceed with the default and
  say so.
- `EqualWeightAllocator` only on Path 3 (selection is the signal); continuous
  forecasts keep conviction through `ForecastWeightNormalizer` or
  `VolTargetWeightConverter` (+ `LeverageCap`) — the validator warns
  `FORECAST_MAGNITUDE_DISCARDED` otherwise.
- Path 3 is `TopNAssetSelector` → `EqualWeightAllocator` →
  `WeightCadence(duration=…)` → `FillNaN(fill_value=0.0)`: the selection feeds
  the allocator directly, the cadence is the hold and the exit, and `FillNaN`
  keeps the terminal weights dense (`NONDENSE_TERMINAL_WEIGHTS` otherwise) —
  the `screen_select_patterns` topic has the validated example. A
  `PositionStateMachine` is followed by a sizer, never preceded by one.
- Start simple: normalization, vol standardization and FDM are follow-ups,
  not defaults, for a single-signal build.

# Output shape

1. The result's `view`: where the host draws it as a card the user already
   sees it — explain it in your own words; elsewhere its markdown stands in.
   The source is in the view; `include_source` fetches it on request.
2. One-sentence thesis ("Trend-following on top-30 HL perps with
   regime-gated vol sizing").
3. The 3–5 composition choices and why.
4. `strategy_id`, `hero_url`, and the declarations the strategy carries
   (Universe, clock, Execution).
5. If a backtest ran: what it says and why.

# When NOT to use

- Modifying an existing strategy → `strategy-fork-and-iterate`.
- Looking up one component → `component-discovery`.
- Repeated tool failures → `recover-from-error`.
- Testing something already authored → `backtest-and-analyze`.

# Test prompts

1. "Build me a momentum strategy on the top 20 HL perps with 1h bars."
2. "Create a new strategy that does EWMAC 8/32 trend following with
   vol-targeted sizing and a beta hedge to BTC."
3. "Make a mean-reversion strategy on ETH using RSI overbought/oversold."
strategy-fork-and-iterate7.29 KB

View saved version →

---
name: strategy-fork-and-iterate
description: |
  Change an existing strategy with one focused edit: the user's own strategy takes the change as its next version (earlier versions and their backtests stay in its history); a shared link or a Keel Library entry is forked first. Read the whole source, choose the smallest edit that meets the intent, dry-run, save once per user-visible step, explain the change view. Use when the user names a strategy and asks for a change, or says "fork", "based on", "like that but ...", "import this share link", "start from the library". Not for authoring from scratch (strategy-creation) or for merely reading a strategy (keel_strategy_get).
references:
  - step: 3
    topic: "dsl_syntax"
    why: "'Strategy Template & Iterative Changes' — which declarations never move without being asked; scope-to-request examples"
  - step: 3
    topic: "composition_mechanics"
    why: "adding a branch: Parallel semantics, branch isolation, the two mask systems"
  - step: 3
    topic: "reasoning_principles"
    why: "invariants a swap must preserve: terminal WeightSeries, one clock, each transform once"
  - step: 4
    topic: "rule:<CODE>"
    why: "the lesson behind a validation issue code the dry run returns"
  - step: 4
    topic: "mistakes"
    why: "structural mistakes to flag (not fix) when you meet them in the existing source"
tools:
  - keel_strategy_search
  - keel_strategy_get
  - keel_strategy_fork
  - keel_library_list
  - keel_library_fork
  - keel_strategy_compose
  - keel_strategy_diff
  - keel_strategy_history
  - keel_strategy_restore
  - keel_backtest_run
---

# References

Reference topics this workflow cites (keel_help topics):

- Step 3 — `dsl_syntax` — 'Strategy Template & Iterative Changes' — which declarations never move without being asked; scope-to-request examples
- Step 3 — `composition_mechanics` — adding a branch: Parallel semantics, branch isolation, the two mask systems
- Step 3 — `reasoning_principles` — invariants a swap must preserve: terminal WeightSeries, one clock, each transform once
- Step 4 — `rule:<CODE>` — the lesson behind a validation issue code the dry run returns
- Step 4 — `mistakes` — structural mistakes to flag (not fix) when you meet them in the existing source

# Method

## Step 1 — Resolve the source

- A strategy id the user owns → go to Step 2. Its variants (a 10D vs 30D
  lookback, a buffer sweep) are VERSIONS of that strategy — one compose save
  each, `message` naming the change — not forks, the same as the Keel app,
  which saves every edit as a version; there are no unsaved variants. A sweep
  is small (2–4 versions): one backtest each, `keel_backtest_compare` once,
  then `keel_strategy_restore(ref=<n>)` makes the chosen version HEAD — HEAD
  is the pick, not whichever version was saved last. Earlier versions and
  their backtests stay in the strategy's history, so a before/after
  comparison needs no fork, and the reply names the save by its version
  (v2, v3 …), never as a fork. Fork only to copy someone else's, a share link or a
  Library strategy, when the user asks for a separate copy, or when the work
  heads in an entirely new direction (Step 3's structural rewrite).
- A share link / share id → `keel_strategy_fork(source=<id>)` → a new owned
  `strategy_id`.
- A Keel Library entry → `keel_library_list` for the slug, then
  `keel_library_fork(slug=...)` → a new owned `strategy_id`.
- "That strategy from last week" → `keel_strategy_search(query=..., limit=5)`,
  confirm which.

## Step 2 — Read the whole source

`keel_strategy_get(strategy_id=<id>, include_source=true)` and read it end to end
before proposing anything — the request often presupposes structure that is
or is not there. (Hosts that browse resources may read
`keel://strategy/<id>/source` instead.)

## Step 3 — Choose the smallest edit

For each requested change, classify it:

- parameter tweak (lookback, threshold) → edit that one value;
- component swap (`EqualWeightSizer` → `VolWeightSizer`) → one component,
  then check the downstream type and any slot it now needs;
- new branch (a filter, a confirmation) → a `Parallel` with the existing
  computation as one branch, not a serial Store/Load chain;
- structural rewrite → push back: "this is a new strategy; want me to draft
  it from scratch?"

Never change the architecture (discrete ↔ continuous, single ↔ multi-signal)
without asking. Never remove or alter anything unrelated to the request; a bug
you notice is a separate question, not a silent fix. `Execution(...)` stays as
it is unless the user asks to change it.

## Step 4 — Dry run, then save once per user-visible step

1. `keel_strategy_compose(strategy_id=<id>, source=<edited>, dry_run=True)` — fix
   what it names (`keel_help(topic="rule:<CODE>")` for the lesson).
2. `keel_strategy_compose(strategy_id=<id>, source=<edited>, message=<the change>)`
   — the next version, visible in `keel_strategy_history` and the web app under
   that message (derived from the change when omitted). A dry run is the
   agent's own check: the user sees one "Draft check" row, so while drafting
   the reply says the draft is being revised rather than quoting parser or
   validator text, unless the user asked for the detail. Save once per
   user-visible step; the save's `view` — its card, which carries the name,
   the change and the links — is what the reply explains, by name. When the
   question is what differs between two strategies or two versions,
   `keel_strategy_diff` answers it (two strategies: pass each one's source)
   and draws the change as a card; the reply names the change in a line
   rather than pasting either source.

## Step 5 — Undo when the user changes their mind

`keel_strategy_history` for the prior version; then
`keel_strategy_restore(strategy_id=<id>, ref=<n>)` — a forward commit that makes
that version HEAD, history preserved (the same as reading it with
`keel_strategy_get(version=<n>, include_source=true)` and saving it again).

# Decision points

- When the user asks for improvements: 1–2 that are useful and easy to
  understand (parameter, buffering, smoothing, a second signal) — never a list
  of ten.
- "Get more trades" → thresholds / filters / hold periods, not a path change;
  "too much turnover" → smooth the signal or `buffered`; "this period was bad"
  → diagnose the mechanism, no rearchitecture.
- A larger change is proposed and waits for the user's approval.

# Output shape

1. The save's `view`: where the host draws it the user already sees it —
   explain it in your own words; elsewhere its markdown stands in.
2. One sentence naming the change ("Swapped equal-weight sizing for
   vol-targeted sizing at 20% annualized").
3. The new `version` and `hero_url`.
4. If the user wants the change tested: a backtest of the new version,
   compared against the previous version's run.

# When NOT to use

- A brand-new strategy → `strategy-creation` (do not fork a nominal template
  for a structurally different idea).
- Just reading a strategy → `keel_strategy_get(include_source=true)`.
- Running the backtest → `backtest-and-analyze`.

# Test prompts

1. "Fork str_K9p2Lz and change the lookback from 20 to 30."
2. "Based on the shared strategy gDXjURKqWPs8CZ4eXdqAI, can you add a BTC
   beta hedge?"
3. "Take my funding-carry strategy and switch it to vol-targeted sizing."
Package details

Publisher declarations from the archived package. These are separate from our research and the live service's terms.

Package author
Keel Software, Inc.

Package observed Nov 2, 2026.

Technical details
First seen
Oct 24, 2026 · 12:40 UTC
Last seen
Nov 3, 2026 · 12:00 UTC
Collection status
Collected

plugin_asdk_app_6abdbe58e6a481919a03773b4c124fe0

Download plugin data (JSON)