Triggers Overview

Triggers are the decision engine of every Botmarley strategy. An action (buy, sell, open position) only executes when its triggers say "go." Without triggers, an action would never fire. Without the right triggers, your strategy would trade at the wrong time.

Think of it this way:

  • An action answers what to do (buy 100 USDC, sell 50%, open a long position).
  • A trigger answers when to do it (RSI dropped below 30, price fell 3% from entry, the 4h candle just closed).

Every action has one or more triggers attached to it. When all of them are satisfied at the same moment, the action fires.

The Three Trigger Types

Botmarley supports three categories of triggers. Each watches a different kind of market signal:

TypeWhat It WatchesExample
TechnicalIndicator values and crossoversRSI(14) drops below 30, SMA(50) crosses above SMA(200)
PriceChangePrice movement, position P&L, time, momentumPrice dropped 3% in the last hour, position is up 2% from entry
NextCandleCandle close eventsThe 4h candle just closed, the daily candle just closed

You will often combine these types on the same action. For example, "buy when the 4h candle closes AND RSI is below 35" uses a NextCandle trigger together with a Technical trigger.

The dedicated chapters cover each type in depth:

AND Logic: Multiple Triggers on One Action

When you attach multiple triggers to a single action, Botmarley treats them as AND conditions. Every trigger must be true simultaneously for the action to fire.

graph LR
    T1["Trigger 1<br/>RSI(14) < 30"]
    T2["Trigger 2<br/>SMA(50) > SMA(200)"]
    T3["Trigger 3<br/>Price fell -3%"]
    AND{{"ALL must<br/>be true"}}
    A["Action fires:<br/>Buy 100 USDC"]

    T1 --> AND
    T2 --> AND
    T3 --> AND
    AND --> A

In TOML, this looks like multiple [[actions.triggers]] blocks under the same [[actions]]:

# This action requires ALL THREE triggers to be true
[[actions]]
type = "open_long"
amount = "100 USDC"

[[actions.triggers]]
indicator = "rsi_14"
operator = "<"
target = "30"
timeframe = "1h"

[[actions.triggers]]
indicator = "sma_50"
operator = ">"
target = "sma_200"
timeframe = "1d"

[[actions.triggers]]
type = "price_change"
value = "-3%"
timeframe = "1h"

Note

There is no OR logic within a single action. If you want "buy when RSI < 30 OR price drops 5%," create two separate actions -- one with the RSI trigger, one with the price drop trigger. Each action fires independently.

The max_count Field

Every trigger type supports an optional max_count field. It limits how many times that trigger can fire per position.

[[actions.triggers]]
type = "pos_price_change"
value = "-2%"
max_count = 1
max_count valueBehavior
Not set (or None)Trigger can fire unlimited times per position
1Trigger fires once per position, then is disabled for that position
3Trigger fires up to 3 times per position

This is essential for DCA (Dollar-Cost Averaging) strategies where you want layered entries. Without max_count, a DCA trigger at -2% would keep firing every time the price bounces back and forth across the -2% threshold. With max_count = 1, it fires once, and you rely on the next DCA level (-4%, -6%) to add more capital.

Tip

A common pattern is to set max_count = 1 on each DCA level so each level fires exactly once per position. This prevents accidental double-buying at the same price level.

How Triggers Reset

Trigger fire counts reset when a new position opens. If a trigger on a DCA action has max_count = 1 and it fires once during Position A, that counter goes back to zero when Position A is closed and Position B is opened later.

The lifecycle looks like this:

graph TD
    A["Position opens"] --> B["Triggers active<br/>fire counts = 0"]
    B --> C{"Trigger<br/>conditions met?"}
    C -- "Yes" --> D["Action fires<br/>fire count += 1"]
    D --> E{"fire count<br/>< max_count?"}
    E -- "Yes" --> C
    E -- "No (or max_count reached)" --> F["Trigger disabled<br/>for this position"]
    C -- "No" --> G["Wait for<br/>next evaluation"]
    G --> C
    F --> H["Position closes"]
    H --> I["All fire counts<br/>reset to 0"]
    I --> A

Warning

max_count is tracked per trigger, per position. If you have two separate actions each with their own -2% trigger and max_count = 1, each of them fires independently -- you would get two buys at the -2% level. Make sure your DCA levels are on separate actions with distinct thresholds.

Putting It All Together

Here is a minimal strategy that demonstrates all three trigger types working together:

[meta]
name = "Triggers Overview Demo"
description = "Shows all three trigger types in one strategy"
max_open_positions = 2

# ENTRY: open when RSI is oversold (Technical)
[[actions]]
type = "open_long"
amount = "100 USDC"

[[actions.triggers]]
indicator = "rsi_14"
operator = "<"
target = "30"
timeframe = "1h"

# DCA: buy more if position drops 3% (PriceChange)
[[actions]]
type = "buy"
amount = "100 USDC"
average_price = true

[[actions.triggers]]
type = "pos_price_change"
value = "-3%"
max_count = 1

# ACCUMULATE: buy on every 4h candle close (NextCandle)
[[actions]]
type = "buy"
amount = "25 USDC"
average_price = true

[[actions.triggers]]
type = "next_candle"
timeframe = "4h"
max_count = 5

# EXIT: sell when position is up 2% (PriceChange)
[[actions]]
type = "sell"
amount = "100%"

[[actions.triggers]]
type = "pos_price_change"
value = "2%"

This strategy opens a position when RSI dips, adds to it on dips and on a schedule, and exits at +2% profit. The max_count values prevent runaway accumulation: the DCA fires once, and the scheduled buys stop after 5 candles.

Continue reading the dedicated chapters for each trigger type to learn all the available fields and see more examples.