Skip to main content
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

SettingTypeDefaultPurpose
strategy_nametext"ETH DCA"User-facing label for the strategy
auto_compoundbooleantrueWhether to reinvest gains
risk_levelsingle_select"medium"Options: low, medium, high
max_orders_per_dayinteger3Cap on daily buy orders
buy_amount_usdnumber50.0USD amount per DCA buy
slippage_tolerancepercentage0.5Max slippage per swap
treasuryaddress"0x1234..."Wallet for fee collection

circuit.toml

circuit.toml
name = "DCA Strategy Agent"
tagline = "Dollar-cost average into tokens"
walletType = "ethereum"
allowedExecutionModes = ["auto", "manual"]
imageUrl = "https://cdn.circuit.org/agents/default"
runtimeIntervalMinutes = 60
version = "0.0.1"

[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"

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

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

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

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

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

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

Example

from agent_sdk import Agent, AgentContext
from agent_sdk.agent_context import CurrentPosition


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 = int(agent.memory.get("orders_today") or "0")
    if orders_today >= max_orders:
        agent.log(f"Daily order limit reached ({orders_today}/{max_orders}), skipping")
        return

    # Execute a swap using the configured amount and slippage
    quote = agent.swap.quote(
        fromNetwork="ethereum:1",
        toNetwork="ethereum:1",
        toToken="0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",  # ETH
        amount=str(int(buy_amount * 1e6)),  # Convert USD to USDC raw units
        slippage=slippage / 100,  # Convert percentage to decimal
    )

    if quote.get("routes"):
        agent.swap.execute(routeId=quote["routes"][0]["routeId"])
        agent.memory.set("orders_today", str(orders_today + 1))
        agent.log(f"DCA buy executed (order {orders_today + 1}/{max_orders})")
    else:
        agent.log("No swap routes available")


def unwind(agent: AgentContext, positions: list[CurrentPosition]) -> None:
    agent.log(f"Unwinding {len(positions)} positions")


agent = Agent(run_function=run, unwind_function=unwind)
handler = agent.get_handler()

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 publish time

Overriding Settings at Session Start

When users start a session, they can override any setting. For example, to run a more aggressive strategy:
{
  "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