Creating a Strategy

This guide walks you through creating a trading strategy from scratch using the MangroveAI API. By the end, you will have a saved strategy ready for backtesting.

Prerequisites

Before you begin, make sure you have:
  • An authentication token. All API calls require a Bearer token. See the Authentication guide for how to obtain one.
  • A basic understanding of signals. You should know the difference between TRIGGER and FILTER signals. If not, read Understanding Signals first.
Set up your token as an environment variable for use throughout this guide:
export TOKEN="your-jwt-token-here"

Step 1: Browse available signals

Start by exploring what signals are available. The signals endpoint returns all 136 active signals with their metadata, parameters, and valid ranges.
curl -s "http://localhost:5001/api/v1/signals?limit=100" | python3 -m json.tool
You can also search for signals by name or keyword:
curl -s -X POST "http://localhost:5001/api/v1/signals/search" \
  -H "Content-Type: application/json" \
  -d '{"query": "macd", "search_type": "name"}'
Not sure which signals to use? Describe your trading idea in plain English using the semantic match endpoint:
curl -X POST "http://localhost:5001/api/v1/signals/match" \
  -H "Content-Type: application/json" \
  -d '{"user_description": "I want to buy when momentum is turning bullish", "num_results": 5}'
The system will suggest matching TRIGGER and FILTER signals.

Step 2: Choose your entry signals

A strategy entry requires exactly 1 TRIGGER and 1 FILTER. For this walkthrough, we will build a trend-following strategy for ETH:
  • TRIGGER: macd_bullish_cross — enters when the MACD line crosses above the signal line
  • FILTER: is_above_sma — confirms the price is above the 50-period Simple Moving Average
First, inspect each signal to understand its parameters:
# Check the TRIGGER signal
curl -s "http://localhost:5001/api/v1/signals/macd_bullish_cross" | python3 -m json.tool

# Check the FILTER signal
curl -s "http://localhost:5001/api/v1/signals/is_above_sma" | python3 -m json.tool
The macd_bullish_cross signal requires three parameters:
  • window_fast (int, range 1-100) — fast EMA period
  • window_slow (int, range 1-200) — slow EMA period
  • window_sign (int, range 1-100) — signal line period
The is_above_sma signal requires one parameter:
  • window (int, range 1-1000) — SMA period
We will use standard values: MACD(12, 26, 9) and SMA(50).

Step 3: Choose exit signals (optional)

Exit signals follow the same pattern: 1 TRIGGER with an optional FILTER. For this strategy, we will add an explicit exit:
  • Exit TRIGGER: macd_bearish_cross — exits when the MACD line crosses below the signal line
If you skip exit signals (pass an empty exit array), the strategy will rely entirely on the built-in stop-loss, take-profit, and time-based exit rules from the execution_config.

Step 4: Create the strategy

Now assemble everything into a POST /api/v1/strategies request. The canonical format uses top-level entry and exit arrays.
curl -s -X POST "http://localhost:5001/api/v1/strategies" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ETH MACD Trend Strategy",
    "asset": "ETH",
    "entry": [
      {
        "name": "macd_bullish_cross",
        "signal_type": "TRIGGER",
        "timeframe": "1h",
        "params": {
          "window_fast": 12,
          "window_slow": 26,
          "window_sign": 9
        }
      },
      {
        "name": "is_above_sma",
        "signal_type": "FILTER",
        "timeframe": "1h",
        "params": {
          "window": 50
        }
      }
    ],
    "exit": [
      {
        "name": "macd_bearish_cross",
        "signal_type": "TRIGGER",
        "timeframe": "1h",
        "params": {
          "window_fast": 12,
          "window_slow": 26,
          "window_sign": 9
        }
      }
    ],
    "reward_factor": 2.0
  }' | python3 -m json.tool
A successful response returns the full strategy object including auto-populated execution_config and execution_state:
{
  "success": true,
  "strategy": {
    "id": "a3f1b2c4-5678-4def-9abc-1234567890ab",
    "name": "ETH MACD Trend Strategy",
    "asset": "ETH",
    "status": "inactive",
    "rules": {
      "name": "eth_macd_trend_strategy",
      "asset": "ETH",
      "entry": [
        {
          "name": "macd_bullish_cross",
          "signal_type": "TRIGGER",
          "timeframe": "1h",
          "params": {"window_fast": 12, "window_slow": 26, "window_sign": 9}
        },
        {
          "name": "is_above_sma",
          "signal_type": "FILTER",
          "timeframe": "1h",
          "params": {"window": 50}
        }
      ],
      "exit": [
        {
          "name": "macd_bearish_cross",
          "signal_type": "TRIGGER",
          "timeframe": "1h",
          "params": {"window_fast": 12, "window_slow": 26, "window_sign": 9}
        }
      ],
      "reward_factor": 2.0
    },
    "execution_config": {
      "max_risk_per_trade": 0.01,
      "reward_factor": 2,
      "stop_loss_calculation": "dynamic_atr",
      "atr_period": 14,
      "atr_volatility_factor": 2.0,
      "cooldown_bars": 24,
      "max_open_positions": 10,
      "max_hold_bars": 50
    },
    "execution_state": {
      "cash_balance": 10000.0,
      "account_value": 10000.0,
      "total_trades": 0,
      "num_open_positions": 0
    },
    "created_at": "2026-02-22T10:30:00Z"
  }
}
You did not provide execution_config or execution_state in the request. The API automatically populates both with defaults from trading_defaults.json. You can override any field by including it in your request. See the Risk Management guide for details on every field.

Step 5: Verify the strategy

Retrieve your newly created strategy to confirm everything was saved correctly:
curl -s -H "Authorization: Bearer $TOKEN" \
  "http://localhost:5001/api/v1/strategies/a3f1b2c4-5678-4def-9abc-1234567890ab" \
  | python3 -m json.tool
You should see:
  • Status: inactive (the default for new strategies)
  • Entry signals: macd_bullish_cross (TRIGGER) + is_above_sma (FILTER)
  • Exit signals: macd_bearish_cross (TRIGGER)

Common validation errors

If your request is rejected, check for these common issues:
ErrorCauseFix
Missing required fields: name, assetMissing top-level fieldsInclude both name and asset in the request body
Multiple TRIGGERs in entryEntry has 2+ signals with signal_type: "TRIGGER"Keep exactly 1 TRIGGER and 1 FILTER for entry
Multiple FILTERs in entryEntry has 2+ signals with signal_type: "FILTER"Keep exactly 1 TRIGGER and 1 FILTER for entry
Signal 'xyz' not foundInvalid signal nameCheck the name against GET /api/v1/signals

What to do next

Your strategy is created and ready to test. Continue with: