Skip to main content
Glama
Keel — Hyperliquid trading strategies

Keel — Hyperliquid trading strategies

by keel-trade

Save Strategy

keel_strategy_compose

Save or version Keel DSL strategies for Hyperliquid: validate and compile source, create new or update existing strategies, or dry-run without saving.

Instructions

Save a strategy from Keel DSL source — new, or with strategy_id its next version; components come from keel_components_search and keel_components_get_many. dry_run=true validates and compiles without saving. Each save of the source adds a new version to the strategy's history and makes it the latest; nothing is deleted, and its earlier versions and their backtests stay in its history.

Declarations, then one Pipeline: 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') A forecast's sign is its direction (positive long, negative short); polarity is trend-following by default, and a mean-reversion signal is the inverted one. A 1d bar closes at 00:00 UTC; bar_offset moves that close, and with it every result.

Unsupported Universe symbols are dropped and named in universe.note; HIP-3 markets (e.g. xyz:AAPL) are not supported yet, coming soon.

A same-machine local checkout is written back (workspace_sync) unless it has local edits; server HEAD is the source of truth.

Tool call template

This tool declares no required parameters. Add optional parameters from the input schema as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {},
    "name": "keel_strategy_compose"
  }
}

Input Schema

NameRequiredDescriptionDefault
nameNoThe strategy's name: required for a new strategy; on an existing one (`strategy_id` set) it sets the name. It names the strategy — its market, thesis or method (e.g. `HYPE MACD trend`) — and is shown wherever the strategy is listed; the user's own name or account belongs to the account, not to a strategy name.
sourceNoThe strategy as Keel DSL text: declarations plus one Pipeline of named components and their parameters, as in the example above. Keel validates it and saves it to the user's Keel account; nothing runs on the user's machine. Exactly one of `source` or `source_file` required.
dry_runNoOnly validate + compile, do not persist.
messageNoOne line naming what this version changes (e.g. `rebalance buffer 10% → 20%`) — its label in the version history. Omitted: derived from the change.
presentNoHow this result displays in the chat — presentation only, no effect on what the tool does. `view`: the full card, for showing the result in full or enlarged. `receipt`: a compact one-line summary row, for the one-line or short version. Omitted: `receipt` for a dry run, `view` for a save.
descriptionNoThe strategy's thesis in the user's own words — one or two sentences on what this strategy is for, which market, and the edge it expects (not a transcript of the conversation). Shown on the strategy page in the Keel app, where the user can edit it. Pass it on create, and again whenever the thesis changes.
source_fileNoPath to a .py DSL file. Exactly one of `source` or `source_file` required.
strategy_idNoIf set, the save adds the next version to this strategy; otherwise a new strategy is created.
component_lockNoOptional component versions to save at, e.g. {"RollingUniverseMask": 2}; on an update, components it does not name keep their saved version; on a create, they start at the latest version, and a pin for a component the source does not use is refused. The result's `component_lock` is the lock that was saved.
parent_versionNoOptional commit/version ref this update is based on.

Output Schema

NameRequiredDescriptionDefault
codeNo
costNo
infoNo
modeNo
nameNo
nextNo
slugNo
viewNoOne strategy: its structure graph, change marks, evidence and the rendered markdown.
addedNo
errorNo
quotaNo
ref_aNo
ref_bNo
staleNo
detailNo
parentNo
reasonNo
resumeNo
run_idNo
sourceNo
changedNo
dry_runNo
exampleNo
messageNo
removedNo
versionNo
categoryNo
compiledNo
docs_urlNo
headlineNo
hero_urlNo
metadataNo
universeNo
url_lineNo
variantsNo
versionsNo
exit_codeNo
fork_noteNo
referenceNoBTC hold, price only, over the run's span (run 1's on a comparison).
reorderedNo
retryableNo
risk_bandNo
share_urlNo
sync_noteNo
unchangedNo
action_urlNo
data_as_ofNo
limit_viewNo
validationNo
variant_idNo
recent_runsNoThe strategy's newest backtest runs, newest first (up to 5): run_id, status, version, the version's commit message, window, completed_at and the headline metrics.
source_slugNo
strategy_idNo
declarationsNo
head_summaryNo
new_sequenceNo
quota_noticeNo
resource_uriNo
source_errorNo
summary_textNo
compile_errorNo
entry_versionNo
error_messageNo
library_factsNo
limit_detailsNo
new_commit_idNo
blocked_actionNo
required_actorNo
talking_pointsNo
versions_errorNo
workspace_syncNo
backtest_windowNo
missing_evidenceNo
ownership_statusNo
unavailable_codeNo
description_errorNo
restored_from_refNo
what_was_expectedNo
default_variant_idNo
is_default_variantNo
unavailable_reasonNo
projection_availableNo
suggested_next_actionNo
ownership_resource_uriNo
restored_from_sequenceNo
live_readiness_blockersNo
next_recommended_actionNo
component_version_changesNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed103 schema fields changedv0.9.0
    • addedInput schema / properties / component_lock
      Added value: +{
      +  "additionalProperties": {
      +    "type": "integer"
      +  },
      +  "description": "Optional component versions to save at, e.g. {\"RollingUniverseMask\": 2}; on an update, components it does not name keep their saved version; on a create, they start at the latest version, and a pin for a component the source does not use is refused. The result's `component_lock` is the lock that was saved.",
      +  "type": "object"
      +}
    • addedInput schema / properties / description
      Added value: +{
      +  "description": "The strategy's thesis in the user's own words — one or two sentences on what this strategy is for, which market, and the edge it expects (not a transcript of the conversation). Shown on the strategy page in the Keel app, where the user can edit it. Pass it on create, and again whenever the thesis changes.",
      +  "maxLength": 2000,
      +  "type": "string"
      +}
    • addedInput schema / properties / message
      Added value: +{
      +  "description": "One line naming what this version changes (e.g. `rebalance buffer 10% → 20%`) — its label in the version history. Omitted: derived from the change.",
      +  "maxLength": 200,
      +  "type": "string"
      +}
    • changedInput schema / properties / name / description
      Previous value: -"Name for the new strategy (create mode)."New value: +"The strategy's name: required for a new strategy; on an existing one (`strategy_id` set) it sets the name. It names the strategy — its market, thesis or method (e.g. `HYPE MACD trend`) — and is shown wherever the strategy is listed; the user's own name or account belongs to the account, not to a strategy name."
    • addedInput schema / properties / name / maxLength
      Added value: +255
    • addedInput schema / properties / name / minLength
      Added value: +1
    • addedInput schema / properties / parent_version / maxLength
      Added value: +200
    • addedInput schema / properties / parent_version / minLength
      Added value: +1
    • addedInput schema / properties / present
      Added value: +{
      +  "description": "How this result displays in the chat — presentation only, no effect on what the tool does. `view`: the full card, for showing the result in full or enlarged. `receipt`: a compact one-line summary row, for the one-line or short version. Omitted: `receipt` for a dry run, `view` for a save.",
      +  "enum": [
      +    "receipt",
      +    "view"
      +  ],
      +  "type": "string"
      +}
    • changedInput schema / properties / source / description
      Previous value: -"DSL source (raw text). Exactly one of `source` or `source_file` required."New value: +"The strategy as Keel DSL text: declarations plus one Pipeline of named components and their parameters, as in the example above. Keel validates it and saves it to the user's Keel account; nothing runs on the user's machine. Exactly one of `source` or `source_file` required."
    • changedInput schema / properties / strategy_id / description
      Previous value: -"If set, updates the named strategy; otherwise creates a new one."New value: +"If set, the save adds the next version to this strategy; otherwise a new strategy is created."
    • addedOutput schema / description
      Added value: +"A strategy result: `view` renders it; an error carries `code` and `message` instead."
    • addedOutput schema / properties / action_url
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / added
      Added value: +{
      +  "type": "array"
      +}
    • addedOutput schema / properties / backtest_window
      Added value: +{}
    • addedOutput schema / properties / blocked_action
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / category
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / changed
      Added value: +{
      +  "type": "array"
      +}
    • addedOutput schema / properties / code
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / compile_error
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / compiled
      Added value: +{
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / component_version_changes
      Added value: +{}
    • addedOutput schema / properties / cost
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / data_as_of
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / declarations
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / default_variant_id
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / description_error
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / detail
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / docs_url
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / dry_run
      Added value: +{
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / entry_version
      Added value: +{}
    • addedOutput schema / properties / error
      Added value: +{}
    • addedOutput schema / properties / error_message
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / example
      Added value: +{}
    • addedOutput schema / properties / exit_code
      Added value: +{
      +  "type": "integer"
      +}
    • addedOutput schema / properties / fork_note
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / head_summary
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / headline
      Added value: +{}
    • addedOutput schema / properties / hero_url
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / info
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / is_default_variant
      Added value: +{
      +  "type": [
      +    "boolean",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / library_facts
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / limit_details
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / limit_view
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / live_readiness_blockers
      Added value: +{
      +  "type": "array"
      +}
    • addedOutput schema / properties / message
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / metadata
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / missing_evidence
      Added value: +{
      +  "type": "array"
      +}
    • addedOutput schema / properties / mode
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / name
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / new_commit_id
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / new_sequence
      Added value: +{
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / next
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / next_recommended_action
      Added value: +{}
    • addedOutput schema / properties / ownership_resource_uri
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / ownership_status
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / parent
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / projection_available
      Added value: +{
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / quota
      Added value: +{
      +  "type": "array"
      +}
    • addedOutput schema / properties / quota_notice
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / reason
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / recent_runs
      Added value: +{
      +  "description": "The strategy's newest backtest runs, newest first (up to 5): run_id, status, version, the version's commit message, window, completed_at and the headline metrics.",
      +  "items": {
      +    "properties": {
      +      "completed_at": {
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "message": {
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "metrics": {
      +        "type": "object"
      +      },
      +      "run_id": {
      +        "type": "string"
      +      },
      +      "status": {
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "version": {
      +        "type": [
      +          "integer",
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "window": {
      +        "type": "object"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / ref_a
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / ref_b
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / reference
      Added value: +{
      +  "description": "BTC hold, price only, over the run's span (run 1's on a comparison).",
      +  "properties": {
      +    "basis": {
      +      "type": "string"
      +    },
      +    "dd_pct": {
      +      "maximum": 0,
      +      "type": "number"
      +    },
      +    "label": {
      +      "type": "string"
      +    },
      +    "ret_pct": {
      +      "type": "number"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / removed
      Added value: +{
      +  "type": "array"
      +}
    • addedOutput schema / properties / reordered
      Added value: +{}
    • addedOutput schema / properties / required_actor
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / resource_uri
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / restored_from_ref
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / restored_from_sequence
      Added value: +{
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
    • removedOutput schema / properties / result
      Removed value: -{
      -  "type": "string"
      -}
    • addedOutput schema / properties / resume
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / retryable
      Added value: +{
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / risk_band
      Added value: +{}
    • addedOutput schema / properties / run_id
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / share_url
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / slug
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / source
      Added value: +{}
    • addedOutput schema / properties / source_error
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / source_slug
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / stale
      Added value: +{
      +  "type": [
      +    "boolean",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / strategy_id
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / suggested_next_action
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / summary_text
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / sync_note
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / talking_points
      Added value: +{
      +  "type": "array"
      +}
    • addedOutput schema / properties / unavailable_code
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / unavailable_reason
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / unchanged
      Added value: +{
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / universe
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / url_line
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / validation
      Added value: +{
      +  "type": "object"
      +}
    • addedOutput schema / properties / variant_id
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / variants
      Added value: +{}
    • addedOutput schema / properties / version
      Added value: +{
      +  "type": [
      +    "integer",
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / versions
      Added value: +{}
    • addedOutput schema / properties / versions_error
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / view
      Added value: +{
      +  "description": "One strategy: its structure graph, change marks, evidence and the rendered markdown.",
      +  "properties": {
      +    "at": {
      +      "type": "string"
      +    },
      +    "categories": {},
      +    "change": {},
      +    "error": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "evidence": {},
      +    "head_version": {
      +      "type": [
      +        "integer",
      +        "null"
      +      ]
      +    },
      +    "header": {},
      +    "kind": {
      +      "const": "strategy"
      +    },
      +    "markdown": {
      +      "type": "string"
      +    },
      +    "marks": {
      +      "type": "boolean"
      +    },
      +    "name": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "object": {
      +      "type": "string"
      +    },
      +    "parse_error": {
      +      "type": "boolean"
      +    },
      +    "previous_version": {},
      +    "seq": {
      +      "type": "integer"
      +    },
      +    "size": {
      +      "type": "string"
      +    },
      +    "source": {},
      +    "status": {},
      +    "status_text": {},
      +    "structure": {},
      +    "url_line": {
      +      "type": "string"
      +    },
      +    "validation": {},
      +    "version": {
      +      "type": [
      +        "integer",
      +        "string",
      +        "null"
      +      ]
      +    }
      +  },
      +  "required": [
      +    "markdown"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / properties / what_was_expected
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / workspace_sync
      Added value: +{
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "result"
      -]
    • removedOutput schema / x-fastmcp-wrap-result
      Removed value: -true
  2. First observedv0.1.0

TDQS

A3.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations establish non-read-only, non-idempotent, non-destructive, and the description adds substantial behavior: each save appends a version and makes it latest, nothing is deleted, earlier versions and their backtests persist, unsupported Universe symbols are dropped and named in `universe.note`, HIP-3 markets unsupported, and a local checkout is written back (`workspace_sync`) unless locally edited, with server HEAD as source of truth. These are exactly the side-effects an agent cannot infer from `destructiveHint: false` alone, and nothing contradicts the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and versioning rules are well front-loaded, and the DSL example is genuinely useful for composing `source`. But the paragraph on forecast sign/polarity and bar-close timing is tangential to saving a strategy and would fit better in a DSL reference, and the description runs long for a save tool with a fully documented schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter, nested-object tool with a full output schema, the description covers the otherwise-invisible parts an agent needs: versioning semantics, dry-run behavior, component-lock sourcing, workspace sync, and symbol-drop reporting. The one gap is the absence of routing guidance against the other strategy-mutation siblings.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description mainly restates schema semantics (`dry_run` validates, `strategy_id` selects update-vs-create) rather than adding new per-parameter meaning; the extra domain detail (bar close at 00:00 UTC, `bar_offset`) refers to DSL constructs, not to any parameter in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Save a strategy from Keel DSL source') and immediately splits the two modes: new strategy vs. next version with `strategy_id`. It also names where components come from (`keel_components_search`, `keel_components_get_many`). It does not differentiate itself from adjacent write-path siblings like `keel_strategy_push`, `keel_strategy_upgrade`, or `keel_strategy_fork`, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives one concrete usage rule (`dry_run=true` validates and compiles without saving) and points at the component tools for sourcing components. However there is no guidance on when to prefer this tool over `keel_strategy_push`, `keel_strategy_upgrade`, `keel_strategy_restore`, or `keel_strategy_fork` — a real ambiguity given the sibling list. Usage is implied rather than delineated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.