> ## Documentation Index
> Fetch the complete documentation index at: https://docs.circuit.org/llms.txt
> Use this file to discover all available pages before exploring further.

# DCA Strategy Agent

> A dollar-cost averaging agent that exercises all seven setting types.

This example demonstrates a DCA (Dollar-Cost Averaging) agent on Ethereum that buys a target token at regular intervals. It exercises all seven setting types available in Circuit.

### Settings Overview

| Setting              | Type            | Default       | Purpose                            |
| -------------------- | --------------- | ------------- | ---------------------------------- |
| `strategy_name`      | `text`          | `"ETH DCA"`   | User-facing label for the strategy |
| `auto_compound`      | `boolean`       | `true`        | Whether to reinvest gains          |
| `risk_level`         | `single_select` | `"medium"`    | Options: low, medium, high         |
| `max_orders_per_day` | `integer`       | `3`           | Cap on daily buy orders            |
| `buy_amount_usd`     | `number`        | `50.0`        | USD amount per DCA buy             |
| `slippage_tolerance` | `percentage`    | `0.5`         | Max slippage per swap              |
| `treasury`           | `address`       | `"0x1234..."` | Wallet for fee collection          |

### circuit.toml

```toml circuit.toml theme={null}
name = "DCA Strategy Agent"
tagline = "Dollar-cost average into tokens"
category = "quant"
imageUrl = "https://cdn.circuit.org/agents/default"
walletType = "ethereum"
allowedExecutionModes = ["auto", "manual"]
runtimeIntervalMinutes = 60

[startingAsset]
network = "ethereum:1"
address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" # USDC
minimumAmount = "100000000" # 100 USDC (6 decimals)

[settings.strategy_name]
description = "User-facing label for the strategy"
type = "text"
default = "ETH DCA"
required = false

[settings.auto_compound]
description = "Whether to reinvest gains"
type = "boolean"
default = true
required = false

[settings.risk_level]
description = "Risk tolerance level"
type = "single_select"
default = "medium"
required = false
options = ["low", "medium", "high"]

[settings.max_orders_per_day]
description = "Cap on daily buy orders"
type = "integer"
default = 3
required = false

[settings.buy_amount_usd]
description = "USD amount per DCA buy"
type = "number"
default = 50.0
required = false

[settings.slippage_tolerance]
description = "Max slippage per swap"
type = "percentage"
default = 0.5
required = false

[settings.treasury]
description = "Wallet for fee collection"
type = "address"
default = "0x1234567890abcdef1234567890abcdef12345678"
required = false
```

### Example

<CodeGroup>
  ```python Python theme={null}
  from circuit_sdk import AgentContext, VirtualAllocation


  def run(agent: AgentContext) -> None:
      # Read all settings — resolved as defaults merged with session overrides
      strategy_name = agent.settings.get("strategy_name")     # str
      auto_compound = agent.settings.get("auto_compound")      # bool
      risk_level = agent.settings.get("risk_level")            # str
      max_orders = agent.settings.get("max_orders_per_day")    # int
      buy_amount = agent.settings.get("buy_amount_usd")        # float
      slippage = agent.settings.get("slippage_tolerance")      # float (0-100)
      treasury = agent.settings.get("treasury")                # str (address)

      agent.log(f"[{strategy_name}] Starting DCA run")
      agent.log(f"  Risk: {risk_level}, Amount: ${buy_amount}, Slippage: {slippage}%")
      agent.log(f"  Max orders: {max_orders}, Auto-compound: {auto_compound}")
      agent.log(f"  Treasury: {treasury}")

      # Check how many orders we've placed today
      orders_today_mem = agent.memory.get("orders_today")
      orders_today = (
          int(orders_today_mem.data.value)
          if orders_today_mem.data and orders_today_mem.data.value is not None
          else 0
      )
      if orders_today >= max_orders:
          agent.log(f"Daily order limit reached ({orders_today}/{max_orders}), skipping")
          return

      # Execute a swap of USDC → ETH using the configured amount and slippage
      usdc = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"  # USDC on Ethereum mainnet
      quote = agent.swap.quote({
          "from": {"network": "ethereum:1", "address": agent.sessionWalletAddress},
          "to": {"network": "ethereum:1", "address": agent.sessionWalletAddress},
          "amount": str(int(buy_amount * 1e6)),  # USD → USDC raw units (6 decimals)
          "fromToken": usdc,
          # toToken omitted → buy native ETH
          "slippage": str(slippage),  # percentage as a string, e.g. "0.5"
      })

      if quote.success and quote.data:
          result = agent.swap.execute(quote.data)
          if result.success:
              agent.memory.set("orders_today", str(orders_today + 1))
              agent.log(f"DCA buy executed (order {orders_today + 1}/{max_orders})")
          else:
              agent.log(result.error or "Swap failed", error=True)
      else:
          agent.log(quote.error or "No swap quote available", error=True)


  def unwind(agent: AgentContext, allocation: VirtualAllocation) -> None:
      agent.log(f"Unwinding {len(allocation.balances)} balances")


  ```

  ```typescript TypeScript theme={null}
  import type { AgentContext, VirtualAllocation } from "circuit:sdk";

  export async function run(agent: AgentContext): Promise<void> {
    // Read all settings — resolved as defaults merged with session overrides
    const strategyName = agent.settings.strategy_name as string;
    const autoCompound = agent.settings.auto_compound as boolean;
    const riskLevel = agent.settings.risk_level as string;
    const maxOrders = agent.settings.max_orders_per_day as number;
    const buyAmount = agent.settings.buy_amount_usd as number;
    const slippage = agent.settings.slippage_tolerance as number;
    const treasury = agent.settings.treasury as string;

    await agent.log(`[${strategyName}] Starting DCA run`);
    await agent.log(`  Risk: ${riskLevel}, Amount: $${buyAmount}, Slippage: ${slippage}%`);
    await agent.log(`  Max orders: ${maxOrders}, Auto-compound: ${autoCompound}`);
    await agent.log(`  Treasury: ${treasury}`);

    // Check how many orders we've placed today
    const ordersTodayMem = await agent.memory.get("orders_today");
    const ordersToday =
      ordersTodayMem.data?.value != null ? parseInt(ordersTodayMem.data.value, 10) : 0;
    if (ordersToday >= maxOrders) {
      await agent.log(`Daily order limit reached (${ordersToday}/${maxOrders}), skipping`);
      return;
    }

    // Execute a swap of USDC → ETH using the configured amount and slippage
    const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; // USDC on Ethereum mainnet
    const quote = await agent.swap.quote({
      from: { network: "ethereum:1", address: agent.sessionWalletAddress },
      to: { network: "ethereum:1", address: agent.sessionWalletAddress },
      amount: String(Math.round(buyAmount * 1e6)), // USD → USDC raw units (6 decimals)
      fromToken: USDC,
      // toToken omitted → buy native ETH
      slippage: String(slippage), // percentage as a string, e.g. "0.5"
    });

    if (quote.success && quote.data) {
      const result = await agent.swap.execute(quote.data);
      if (result.success) {
        await agent.memory.set("orders_today", String(ordersToday + 1));
        await agent.log(`DCA buy executed (order ${ordersToday + 1}/${maxOrders})`);
      } else {
        await agent.log(result.error || "Swap failed", { error: true });
      }
    } else {
      await agent.log(quote.error || "No swap quote available", { error: true });
    }
  }

  export async function unwind(agent: AgentContext, allocation: VirtualAllocation): Promise<void> {
    await agent.log(`Unwinding ${allocation.balances.length} balances`);
  }

  ```
</CodeGroup>

### How It Works

1. **Read settings**: All seven setting types are read from `agent.settings` as their native runtime types — strings, booleans, and numbers
2. **Rate limiting**: Uses `integer` setting (`max_orders_per_day`) with agent memory to enforce a daily order cap
3. **Swap execution**: Uses `number` setting (`buy_amount_usd`) and `percentage` setting (`slippage_tolerance`) to configure the swap parameters
4. **Address tracking**: The `address` setting (`treasury`) is validated against the agent's `walletType` at upload time

### Overriding Settings at Session Start

When users start a session, they can override any setting. For example, to run a more aggressive strategy:

```json theme={null}
{
  "settings": [
    { "key": "risk_level", "value": { "text": "high" } },
    { "key": "buy_amount_usd", "value": { "number": 100 } },
    { "key": "slippage_tolerance", "value": { "number": 1.0 } },
    { "key": "max_orders_per_day", "value": { "number": 5 } }
  ]
}
```

Numeric types (`integer`, `number`, `percentage`) all use `{ "number": N }` on the wire. The setting's `type` determines validation rules (whole numbers for `integer`, 0-100 range for `percentage`).

### See Also

* [Settings SDK Reference](../sdk-reference/settings) — Accessing settings at runtime
* [`circuit.toml` Reference](../getting-started/circuit-toml-reference#settings-section) — Defining settings
