Skip to content

Example strategy

example is the reference template for a Dyson strategy executable, not a strategy anyone runs. Copy it when creating a new strategy package and adapt only the concrete process wiring that differs.

It is also the shortest way to understand what any strategy binary is responsible for.

The data model

Strategy -> StrategyVersion -> Deployment -> Run

MongoDB supplies the selected immutable RuntimeConfig; NATS supplies commands and market-data events. The executable combines those with a venue client and a post-trade sink.

Bootstrap order

flowchart TD
    A["Read deployment_id from the command line"]
    B["Load MongoDB connection settings"]
    C["Resolve Deployment → StrategyVersion<br/>and validate its native config"]
    D["Build market, guarded execution client, post-trade sink"]
    E["Construct ProcessSupervisor with a new run_id"]
    F["Connect NATS, enter the serialized event loop"]
    G["Wait in Loaded for a Start command"]

    A --> B --> C --> D --> E --> F --> G

    classDef gate fill:#2e7d32,stroke:#1b5e20,color:#fff
    class C gate

Validation happens before credentials can submit orders. That ordering is the point of the template: an invalid config fails while the process is still harmless.

What the template deliberately does not do

  • It does not launch the upstream algo_mm_bot.
  • It does not implement its own lifecycle machine.
  • It does not read MongoDB while processing market data.

If a copied strategy starts doing any of these, it has drifted from the shared runtime contract.

Creating a strategy from it

cp -R strategies/example strategies/btc-quoter

Then:

  1. Change name in the copied Cargo.toml (for example dyson-btc-quoter).
  2. Update USAGE in src/main.rs for the new binary name.
  3. Keep the existing bootstrap if the strategy uses Kuru, the central market envelope, and the native post-trade sink.
  4. Replace only the venue construction, decoder, or sink that genuinely differs.
  5. Replace the smoke-test binary name and add tests for custom wiring.
  6. Write the strategy's operating notes into its copied README.

The workspace already globs strategies/*, so a copied package is discovered automatically.

Two standing rules

Reusable logic does not belong in a strategy binary — move shared behavior into a main-repository crate. And everything under external/ is read-only.

Configuration documents

A strategy needs two MongoDB documents. The version holds the complete native config and is immutable:

{
  "strategy_id": "Strategy:btc-quoter",
  "version_id": "btc-quoter-v20260717.001",
  "config": {
    "strategy_id": "Strategy:btc-quoter",
    "venue": {
      "type": "Kuru",
      "instrument": "KURU.BTCUSDC",
      "tick_size": 0.01,
      "market_address": "0x...",
      "symbol": "BTC_USDC"
    },
    "strategy": {
      "actors": [],
      "signals": [],
      "feeds": [{ "instrument": "KURU.BTCUSDC" }],
      "pnl_monitor_params": {
        "drawdown_reduce": 500,
        "drawdown_shutdown": 1500
      }
    },
    "post_trade": { "jsonl_path": "logs/btc-quoter.jsonl" }
  }
}

The deployment selects that version and records provenance:

{
  "deployment_id": "deploy-btc-prod-kuru",
  "strategy_id": "Strategy:btc-quoter",
  "version_id": "btc-quoter-v20260717.001",
  "source_commit": "<full-git-commit-sha>",
  "config_hash": "sha256:<canonical-config-hash>",
  "environment": "production"
}

All three strategy_id values must match, and source_commit and config_hash are required and must not be blank. Fixtures under crates/database/tests/fixtures/mongodb are local seed examples — their dummy market and provenance values must never be used for live trading.

Running it

cargo run -p dyson-example-strategy -- deploy-btc-prod-kuru

The process validates configuration and publishes Loaded. It trades only once started:

nats pub strategy.commands.deploy-btc-prod-kuru \
  '{"type":"start","command_id":"start-001"}'

Other commands use the same subject and shape — pause, resume, drain, stop, shutdown. Repeated command IDs are ignored, which is what makes redelivery safe. Market envelopes arrive on marketdata.>; status and events go to strategy.status.{strategy_id}.{run_id} and strategy.events.{strategy_id}.{run_id}. Ctrl-C requests graceful shutdown and cancellation of outstanding orders.

New-strategy checklist

  • Package and binary names are unique.
  • Strategy, version, and deployment IDs are consistent.
  • The native config passes validation before credentials can submit orders.
  • Deployment provenance records the exact clean source commit and config hash.
  • Market-data subjects and instruments match the configured feeds.
  • Risk limits and post-trade output paths are explicit.
  • Lifecycle and shutdown continue to use dyson-runtime.
  • Smoke, focused, workspace, and diff-coverage checks pass.
  • No file under external/ was modified.