Dynamic Stop Loss (DSL) v5.3.1
Scope — DSL only. This skill handles only dynamic/trailing stop loss (DSL), not normal (static) stop loss. If the user says "stop loss" without clearly meaning DSL or static, ask (e.g. "Do you want a trailing stop that moves up with profit, or a fixed price stop loss?").
User-facing language. Use plain terms ("trailing stop", "profit protection"). Do not mention state paths, cron IDs, script names, or DSL_* env unless the user asks for technical details.
Default Mode: High Water
All new positions should use High Water Mode (lockMode: "pct_of_high_water"). This is the recommended default for every Senpi skill. The trailing floor is a percentage of the peak ROE, recalculated on every tick, with no ceiling. A trade at +50% ROE with 85% lock has its floor at +42.5%. A trade at +200% ROE has its floor at +170%. The geometry is constant — the trade always keeps 85% of its best moment.
See dsl-high-water-spec 1.0.md for the full spec and dsl-high-water-adoption-guide.md for per-skill tier configurations.
When creating DSL state files, ALWAYS include:
{
"lockMode": "pct_of_high_water",
"tiers": [
{"triggerPct": 7, "lockHwPct": 40, "consecutiveBreachesRequired": 3},
{"triggerPct": 12, "lockHwPct": 55, "consecutiveBreachesRequired": 2},
{"triggerPct": 15, "lockHwPct": 75, "consecutiveBreachesRequired": 2},
{"triggerPct": 20, "lockHwPct": 85, "consecutiveBreachesRequired": 1}
]
}
Use the per-skill tiers from dsl-high-water-adoption-guide.md — different skills have different tier widths. The above is the standard momentum default (FOX, HAWK, DIRE WOLF).
Legacy mode (lockMode: "fixed_roe" or omitted) still works for existing positions. lockPct tiers lock a fixed fraction of the entry→HW price range. No per-tick recalculation — floor only updates on tier changes.
Trailing stop for Hyperliquid perps (main + xyz). Default: High Water Mode — floor trails the peak ROE as a percentage, recalculated every tick, no ceiling. Cron runs dsl-v5.py every 3–5 min; the script syncs the current floor to Hyperliquid via Senpi edit_position so HL can execute the SL even if the cron process goes down. Phase 1: wide retrace with absolute floor cap. Phase 2: tiered High Water locks that ratchet up with profit and never come back down. See references/tier-examples.md and references/state-schema.md.
Files: scripts/dsl-v5.py (monitor/close, ndjson output), scripts/dsl-cleanup.py (strategy dir cleanup), scripts/dsl-cli.py (lifecycle — use for all setup). Config: dsl-profile.json (this skill’s default). State: {DSL_STATE_DIR}/{strategyId}/{asset}.json; strategy config: references/strategy-schema.md. Cleanup: references/cleanup.md. Output schema: references/output-schema.md.
Architecture
- Scheduler: OpenClaw cron (one per strategy, every 3–5 min). No per-position cron — the script discovers positions from MCP clearinghouse and state files.
- Cron runner:
dsl-v5.py— accepts--strategy-id <uuid>and--state-dir <path>(CLI args take precedence; env varsDSL_STRATEGY_ID,DSL_STATE_DIRare fallbacks). Prefer CLI args to avoid agent mistyping UUID in env. Checks strategy active (MCPstrategy_get); reconciles state files with clearinghouse (archives orphans); for each active position: fetch price, update high water and tiers, sync SL to Hyperliquid viaedit_position, detect breach, on breach callclose_positionand archive state. Prints one JSON line per position (ndjson). - Lifecycle:
dsl-cli.pycreates/updates strategy config and position state files only (it does not place the SL order). The cron runner syncs the floor to Hyperliquid viaedit_positionand setsslOrderIdin state. When adding DSL for a strategy with no cron, CLI outputscron_needed,cron_job_id,cron_env,cron_schedule. Agent creates or removes the OpenClaw cron using that ID. - Cleanup: On strategy inactive or no positions left, agent runs
dsl-cleanup.pyto remove the strategy directory. SL sync and close use Senpi (mcporter); scheduling is OpenClaw only.
┌─────────────────────────────────────────────────────────────────┐
│ OpenClaw cron (per strategy) → dsl-v5.py │
│ MCP: strategy_get, clearinghouse, prices, edit_position, │
│ close_position, execution_get_order_status │
│ Output: ndjson (one line per position or strategy-level) │
├─────────────────────────────────────────────────────────────────┤
│ Agent: create/remove cron from CLI output; run dsl-cleanup; │
│ alert on closed / strategy_inactive / pending_close │
└─────────────────────────────────────────────────────────────────┘
CLI commands
All lifecycle operations use scripts/dsl-cli.py. Global option: --state-dir (default: $DSL_STATE_DIR or /data/workspace/dsl). Config must be a file path with @ prefix (e.g. @dsl-profile.json) or inline JSON.
| Command | Usage | Notes |
|---|---|---|
| add-dsl | add-dsl <strategy-id> [asset dex] --skill <skill-name> --configuration @<path> | Creates strategy config and position state files. Omit asset/dex for all positions. Optional --entry-price. Output: cron_needed, cron_job_id, cron_env, cron_schedule when cron must be created. |
| update-dsl | update-dsl <strategy-id> [asset dex] --configuration <json-or-@path> | Strategy-wide or per-position config patch (e.g. '{"phase1":{"retraceThreshold":0.05}}' or @override.json). |
| pause-dsl | pause-dsl <strategy-id> [asset dex] | Pause monitoring; cron keeps running, state preserved. |
| resume-dsl | resume-dsl <strategy-id> [asset dex] | Resume monitoring. |
| delete-dsl | delete-dsl <strategy-id> [asset dex] | Archive state and tear down. Output: cron_to_remove when agent must remove OpenClaw cron. |
| status-dsl | status-dsl <strategy-id> [asset dex] | Report current status. |
| count-dsl | count-dsl <strategy-id> | Aggregate counts. |
| validate | validate --configuration @<path> | Validate a DSL config file (e.g. @dsl-profile.json). |
Examples (this skill): --skill dsl-dynamic-stop-loss --configuration @<path-to-this-skill>/dsl-profile.json. Other skills: same CLI with --skill <their-skill> and --configuration @<their-dsl-profile.json>. Full details: references/cli-usage.md.
This skill (direct DSL setup)
When the user asks for trailing/dynamic stop loss, use scripts/dsl-cli.py for all lifecycle operations (do not edit state files by hand unless CLI is unavailable).
- Add DSL:
python3 scripts/dsl-cli.py add-dsl <strategy-id> [asset dex] --skill dsl-dynamic-stop-loss --configuration @<path-to-this-skill>/dsl-profile.json - If output has
cron_needed: true, create the OpenClaw cron with the outputcron_job_id,cron_env, andcron_schedule(schedule is derived fromcronIntervalMinutes, default 3; one cron per strategy). - Update / Pause / Resume / Delete / Status / Count: use the commands in the table above (same CLI, same
--skilland--configurationas for add).
Agent: On closed=true → alert user. On strategy_inactive → remove cron, run dsl-cleanup.py. On pending_close=true → alert (script retries). On delete-dsl output cron_to_remove → remove that cron. On update-dsl output cron_schedule_changed: true → remove the existing cron (using cron_to_remove.cron_job_id) and create a new one with the same cron_job_id and the new cron_schedule (interval is configurable via cronIntervalMinutes; default 3 min).
Other skills: setting up DSL
Full integration guide: references/integration-guide.md — step-by-step for any skill (paths, add/delete-dsl, cron, cleanup, checklist).
Any skill (e.g. wolf-strategy, dsl-tight) can add DSL for its strategies by calling the same CLI with its own profile and skill name.
- Locate
dsl-cli.py(e.g.dsl-dynamic-stop-loss/scripts/dsl-cli.py) and your skill’s dsl-profile.json (in your skill directory). Resolve paths at runtime. - Add DSL:
python3 <path>/dsl-cli.py add-dsl <strategy-id> [asset dex] --skill <your-skill-name> --configuration @<path-to-your-dsl-profile.json>
Use@before the config path so the CLI reads the file (without@it treats the value as inline JSON). - Cron: If the CLI output includes
cron_needed: true, it also includescron_job_id,cron_env,cron_schedule. Create the OpenClaw cron with that ID and env/schedule (one cron per strategy). - Lifecycle: For update, pause, resume, delete, status, count use the same CLI and the commands in the CLI commands table above (same
--skilland--configurationas for add). See references/cli-usage.md for examples. - Agent duties: Same as this skill — on
closed=truealert user; onstrategy_inactiveremove cron and rundsl-cleanup.py; oncron_to_removeremove that OpenClaw cron.
Example (other skill, single position):
python3 /path/to/dsl-dynamic-stop-loss/scripts/dsl-cli.py add-dsl <strategy-id> ETH main \
--skill wolf-strategy \
--configuration @/path/to/wolf-strategy/dsl-profile.json
Full command reference and configuration merge rules: references/cli-usage.md.
References
| Topic | Reference |
|---|---|
| Integrating another skill with DSL | references/integration-guide.md |
| CLI commands and inter-skill usage | references/cli-usage.md |
| State and strategy schema | references/state-schema.md, references/strategy-schema.md |
| Output (ndjson) and agent actions | references/output-schema.md |
| Cleanup (strategy dir, cron removal) | references/cleanup.md |
| Tier math, LONG/SHORT | references/tier-examples.md |
| Config tuning | references/customization.md |
| Cron-only → HL SL migration | references/migration.md |
| ROE-based → High Water migration (recommended for existing state) | references/migration.md |
API: Strategy/positions/price/close and SL sync via Senpi (mcporter). Do not use strategy_close_strategy for a single position — use close_position.
Changelog
| Version | Date | Changes |
|---|---|---|
| v5.3.1 | 2026-03-13 | High Water: infinite trail, SL sync when floor moves; spec checklist tests |
| v5.3 | 2026-03-12 | High Water Mode: lockMode: "pct_of_high_water", lockHwPct per tier |
| v5.2 | 2026-03-01 | CLI lifecycle manager, multi-skill integration, SL order verification, reconciliation archive types, cronIntervalMinutes, config validation |
| v5.0 | — | Two-phase trailing stop, exchange SL sync |