backtester

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PlausibleAI Backtester

PlausibleAI Backtester

How to Use This Skill

如何使用该技能

When this skill is active, use the guidance below directly. Do not perform filesystem searches or tool-driven exploration to rediscover it.
Use the PlausibleAI publisher API as the source of truth for symbol discovery, DSL discovery, validation, and execution. Prefer validating unfamiliar payloads before running them.
当该技能激活时,请直接遵循以下指引操作。无需执行文件系统搜索或工具驱动的探索来重新查找相关内容。
请将PlausibleAI发布者API作为标的发现、DSL发现、验证和执行的权威来源。在运行不熟悉的请求负载前,优先进行验证。

Base Route

基础路由

All routes go through
https://api.serendb.com/publishers/plausibleai
.
所有请求均通过
https://api.serendb.com/publishers/plausibleai
发送。

Authentication

身份验证

All endpoints require
Authorization: Bearer $SEREN_API_KEY
.
所有端点均要求携带
Authorization: Bearer $SEREN_API_KEY
请求头。

Workflow

工作流程

  1. Resolve auth. Set
    SEREN_API_KEY
    for bearer auth. Use
    SEREN_PUBLISHER_BASE_URL
    in examples; default it to
    https://api.serendb.com/publishers/plausibleai
    .
  2. Discover the market universe before guessing symbols. Call
    GET /api/markets/types
    to see supported market types and symbol counts. Call
    GET /api/markets/symbols
    with
    market_type
    ,
    search
    ,
    limit
    , and
    offset
    when the symbol is unknown. Call
    GET /api/markets/symbols/{symbol}
    when the caller needs metadata or data availability.
  3. Load the DSL contract. Call
    GET /api/backtests/catalog
    before composing a new request shape. Treat the catalog as authoritative for indicators, parameters, operators, logic nodes, examples,
    price_adjustment_modes
    ,
    entry_price_bases
    , and response metric definitions.
  4. Build the request with stable rule ids. Every entry or exit rule must include a unique
    id
    . Logic nodes reference rules by
    id
    , never by position. If
    logic
    is omitted, the API combines all rules in the set with
    AND
    .
  5. Validate novel requests. Use
    POST /api/backtests/validate
    when the request uses a new symbol, a new indicator combination, or a non-trivial logic tree. Surface validation errors directly instead of trying to guess what the API intended.
  6. Execute. Use
    POST /api/backtests
    for a single run. Use
    POST /api/backtests/batch
    when the caller wants multiple independent runs. Batch requests run concurrently on the server; order in the response is stable regardless of completion order. Single-run backtests are also stored as short-lived retrievable results. The response body is a compact stored-result summary with
    id
    ,
    expires_at
    , and follow-up links for fetching the full result, trades, and equity curve.
  7. Mine when the caller wants "the best actionable signal now". Use
    POST /api/backtests/mine
    . Minimal request is just
    { "symbol": "BTC-USD" }
    . Mining defaults to a sensible rolling window and ranks candidates by
    profit_factor
    unless overridden. Mining returns a compact summary plus a nested
    backtest
    handle with
    id
    ,
    expires_at
    , and follow-up links.
  8. Retrieve large result sections incrementally. Use
    GET /api/backtests/{id}
    for the stored full result. Use
    GET /api/backtests/{id}/trades
    for the full trade list, or add
    ?limit=&offset=
    when pagination is needed. Use
    GET /api/backtests/{id}/equity-curve
    for the full equity curve, or add
    ?limit=&offset=
    when pagination is needed. Stored results are ephemeral and expire automatically.
  9. Interpret the result carefully.
    report
    is the summary.
    benchmarks.buy_and_hold
    is the buy-and-hold comparison over the same range.
    execution.provider_symbol
    shows the provider-native symbol actually used after the backend auto-resolves the best data source.
    trades
    are closed trades. Each trade includes
    trade_number
    ,
    side
    ,
    entry_bar_index
    ,
    exit_bar_index
    ,
    entry_date
    ,
    exit_date
    ,
    pnl
    ,
    duration_bars
    , and
    exit_reason
    .
    trades[].exit_reason
    is a snake_case string from a documented set:
    take_profit
    ,
    stop_loss
    ,
    trailing_stop
    ,
    highest_high_exit
    ,
    lowest_low_exit
    ,
    exit_signal
    ,
    end_of_data
    ,
    other
    . The full list is in
    catalog.trade_exit_reasons
    .
    equity_curve
    is trade-indexed, not bar-indexed, and uses the same
    trade_number
    values as
    trades
    . Top-level
    first_entry_signal_at
    and
    last_entry_signal_at
    refer to entry signals only.
    diagnostics
    reports signal counts and per-rule signal summaries using rule ids.
  1. 完成身份验证配置 设置
    SEREN_API_KEY
    以使用Bearer身份验证。示例中使用
    SEREN_PUBLISHER_BASE_URL
    ,默认值为
    https://api.serendb.com/publishers/plausibleai
  2. 在猜测标的前先探索市场范围 调用
    GET /api/markets/types
    查看支持的市场类型及标的数量。 当标的未知时,携带
    market_type
    search
    limit
    offset
    参数调用
    GET /api/markets/symbols
    。 当调用者需要标的元数据或数据可用性信息时,调用
    GET /api/markets/symbols/{symbol}
  3. 加载DSL合约 在构建新请求结构前,先调用
    GET /api/backtests/catalog
    。 请将该目录作为指标、参数、运算符、逻辑节点、示例、
    price_adjustment_modes
    entry_price_bases
    和响应指标定义的权威来源。
  4. 使用稳定的规则ID构建请求 每个入场或离场规则都必须包含唯一的
    id
    。 逻辑节点通过
    id
    引用规则,而非通过位置引用。 如果省略
    logic
    参数,API会将规则集中的所有规则通过
    AND
    逻辑组合。
  5. 验证新请求 当请求使用新标的、新指标组合或复杂逻辑树时,使用
    POST /api/backtests/validate
    进行验证。 直接展示验证错误,无需猜测API的预期逻辑。
  6. 执行回测 单次回测使用
    POST /api/backtests
    接口。 当调用者需要多次独立回测时,使用
    POST /api/backtests/batch
    接口。批量请求会在服务器上并发执行;响应结果的顺序与完成顺序无关,保持稳定。 单次回测的结果也会作为短期可检索结果存储。响应体是一个简洁的存储结果摘要,包含
    id
    expires_at
    以及用于获取完整结果、交易记录和权益曲线的后续链接。
  7. 当调用者需要“当前可执行的最优信号”时,使用策略挖掘功能 调用
    POST /api/backtests/mine
    接口。 最简请求仅需包含
    { "symbol": "BTC-USD" }
    。 挖掘功能默认使用合理的滚动窗口,并以
    profit_factor
    作为候选策略的排序依据,除非显式覆盖该配置。 挖掘功能返回简洁摘要,以及包含
    id
    expires_at
    和后续链接的嵌套
    backtest
    句柄。
  8. 增量检索大型结果集 使用
    GET /api/backtests/{id}
    获取完整的存储结果。 使用
    GET /api/backtests/{id}/trades
    获取完整交易记录,当需要分页时可添加
    ?limit=&offset=
    参数。 使用
    GET /api/backtests/{id}/equity-curve
    获取完整权益曲线,当需要分页时可添加
    ?limit=&offset=
    参数。 存储的结果为临时数据,会自动过期。
  9. 仔细解读回测结果
    report
    字段为结果摘要。
    benchmarks.buy_and_hold
    为相同时间范围内的买入持有策略对比数据。
    execution.provider_symbol
    显示后端自动解析最优数据源后实际使用的供应商原生标的。
    trades
    为已平仓交易记录。每条交易包含
    trade_number
    side
    entry_bar_index
    exit_bar_index
    entry_date
    exit_date
    pnl
    duration_bars
    exit_reason
    trades[].exit_reason
    为文档中定义的蛇形命名字符串,可选值包括:
    take_profit
    stop_loss
    trailing_stop
    highest_high_exit
    lowest_low_exit
    exit_signal
    end_of_data
    other
    。完整列表可在
    catalog.trade_exit_reasons
    中查看。
    equity_curve
    按交易索引而非K线索引生成,与
    trades
    中的
    trade_number
    值对应。 顶层字段
    first_entry_signal_at
    last_entry_signal_at
    仅指代入场信号的时间。
    diagnostics
    字段报告信号数量以及按规则ID统计的单规则信号摘要。

Indicator Quick Reference

指标速查

KeyCategoryRequired ParamsOptional Params / Notes
sma
trend
period
(int)
source
(default:
close
)
ema
trend
period
(int)
source
(default:
close
)
adx
trend
period
(int)
positive_directional_indicator
trend
period
(int)
negative_directional_indicator
trend
period
(int)
parabolic_sar
trend
af_step
(float, e.g. 0.02),
af_max
(float, e.g. 0.20)
Returns +1 (uptrend) or -1 (downtrend); compare against 0
rsi
momentum
period
(int)
source
(default:
close
)
stochastic_oscillator
momentum
period
(int)
range 0–100
momentum
momentum
period
(int)
cci
momentum
period
(int)
roc
momentum
period
(int)
macd_line
momentum
fast
,
slow
,
signal
(all int, fast < slow)
macd_signal_line
momentum
fast
,
slow
,
signal
(all int, fast < slow)
macd_histogram
momentum
fast
,
slow
,
signal
(all int, fast < slow)
tsi
momentum
long_period
(int),
short_period
(int, must be < long_period)
range: -100 to +100
atr
volatility
period
(int)
source not accepted
atr_percent
volatility
period
(int)
bollinger_upper_band
volatility
period
,
num_std
bollinger_lower_band
volatility
period
,
num_std
standard_deviation
volatility
period
(int)
source
(default:
close
)
keltner_upper_band
volatility
period
(int),
multiplier
(float)
keltner_lower_band
volatility
period
(int),
multiplier
(float)
highest
price_action
period
(int)
source
(default:
high
)
lowest
price_action
period
(int)
source
(default:
low
)
day_of_week
seasonalSun=0, Mon=1 … Fri=5, Sat=6; use
eq
to target a specific day
day_of_month
seasonal1–31
week_of_month
seasonal1–5; resets on month change
month
seasonal1–12
quarter
seasonal1–4
period
is always required — the server never defaults it. The catalog
indicators[].parameters
array is the source of truth.
键名分类必填参数可选参数 / 说明
sma
趋势类
period
(整数)
source
(默认值:
close
)
ema
趋势类
period
(整数)
source
(默认值:
close
)
adx
趋势类
period
(整数)
positive_directional_indicator
趋势类
period
(整数)
negative_directional_indicator
趋势类
period
(整数)
parabolic_sar
趋势类
af_step
(浮点数,例如0.02),
af_max
(浮点数,例如0.20)
返回+1(上涨趋势)或-1(下跌趋势);需与0进行比较
rsi
动量类
period
(整数)
source
(默认值:
close
)
stochastic_oscillator
动量类
period
(整数)
取值范围0–100
momentum
动量类
period
(整数)
cci
动量类
period
(整数)
roc
动量类
period
(整数)
macd_line
动量类
fast
,
slow
,
signal
(均为整数,fast < slow)
macd_signal_line
动量类
fast
,
slow
,
signal
(均为整数,fast < slow)
macd_histogram
动量类
fast
,
slow
,
signal
(均为整数,fast < slow)
tsi
动量类
long_period
(整数),
short_period
(整数,必须小于long_period)
取值范围: -100 至 +100
atr
波动率类
period
(整数)
不接受source参数
atr_percent
波动率类
period
(整数)
bollinger_upper_band
波动率类
period
,
num_std
bollinger_lower_band
波动率类
period
,
num_std
standard_deviation
波动率类
period
(整数)
source
(默认值:
close
)
keltner_upper_band
波动率类
period
(整数),
multiplier
(浮点数)
keltner_lower_band
波动率类
period
(整数),
multiplier
(浮点数)
highest
价格行为类
period
(整数)
source
(默认值:
high
)
lowest
价格行为类
period
(整数)
source
(默认值:
low
)
day_of_week
季节性类周日=0, 周一=1 … 周五=5, 周六=6;使用
eq
运算符指定具体日期
day_of_month
季节性类1–31
week_of_month
季节性类1–5;每月重置
month
季节性类1–12
quarter
季节性类1–4
period
参数始终为必填项——服务器不会为其设置默认值。
catalog.indicators[].parameters
数组是参数的权威来源。

Execution Block Quick Reference

执行块速查

FieldTypeRequiredNotes
side
"long"
|
"short"
yestrade direction
entry_mode
enumyes
this_bar_close
,
next_bar_open
(most common),
next_bar_limit
,
next_bar_stop
atr_period
integernoused when any ATR-based entry offset or exit is present; defaults to
20
when omitted
entry_price
{basis, lookback, offset}
noonly valid with
next_bar_limit
or
next_bar_stop
; bases:
none
,
highest_high
,
lowest_low
;
offset
is
{mode, value}
and moves the reference price up or down
字段类型必填说明
side
"long"
|
"short"
交易方向
entry_mode
枚举值
this_bar_close
,
next_bar_open
(最常用),
next_bar_limit
,
next_bar_stop
atr_period
整数当存在任何基于ATR的入场偏移或离场设置时使用;若省略则默认值为
20
entry_price
{basis, lookback, offset}
仅在
next_bar_limit
next_bar_stop
模式下有效;basis可选值:
none
,
highest_high
,
lowest_low
offset
{mode, value}
,用于调整参考价格的上下浮动

Exit Policy Quick Reference

离场规则速查

Price-based exits go in
exits
. A rule-based signal exit goes in
exit_signal
.
FieldTypeMode optionsNotes
exits.stop_loss
{mode, value}
fixed
,
percent
,
atr
value > 0
exits.take_profit
{mode, value}
fixed
,
percent
,
atr
value > 0
exits.trailing_stop
{mode, value}
fixed
,
percent
,
atr
value > 0
exits.max_hold_bars
integerexits after N bars
exits.profitable_closes
integerexits after N cumulative profitable closes since entry
exits.highest_high_exit_lookback
integerexits at the rolling highest high over N bars
exits.lowest_low_exit_lookback
integerexits at the rolling lowest low over N bars
exit_signal
rule setrule-based exit logic that can be combined with price exits
If any ATR-based entry offset or exit is present and
execution.atr_period
is omitted, the API defaults it to
20
.
entry_price
is only valid with
entry_mode: next_bar_limit
or
next_bar_stop
.
基于价格的离场设置需放在
exits
字段中。基于规则信号的离场设置需放在
exit_signal
字段中。
字段类型模式选项说明
exits.stop_loss
{mode, value}
fixed
,
percent
,
atr
value > 0
exits.take_profit
{mode, value}
fixed
,
percent
,
atr
value > 0
exits.trailing_stop
{mode, value}
fixed
,
percent
,
atr
value > 0
exits.max_hold_bars
整数持有N根K线后离场
exits.profitable_closes
整数累计N次盈利平仓后离场
exits.highest_high_exit_lookback
整数在N根K线内的最高点离场
exits.lowest_low_exit_lookback
整数在N根K线内的最低点离场
exit_signal
规则集基于规则的离场逻辑,可与价格离场设置组合使用
如果存在任何基于ATR的入场偏移或离场设置,且未指定
execution.atr_period
,API会将其默认值设为
20
entry_price
仅在
entry_mode: next_bar_limit
next_bar_stop
模式下有效。

Example Strategies

示例策略

Use these as canonical request patterns for the main DSL surfaces.
以下为DSL核心功能的标准请求示例。

1. Trend Following: 50/200 SMA Golden Cross

1. 趋势跟踪:50/200 SMA黄金交叉

Good default example for rule ids and
exit_signal
.
json
{
  "symbol": "BTC-USD",
  "timeframe": "daily",
  "start_at": "2020-01-01",
  "initial_capital": 100000,
  "execution": {
    "side": "long",
    "entry_mode": "next_bar_open"
  },
  "entry": {
    "rules": [
      {
        "id": "golden_cross",
        "lhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 50,
              "source": "close"
            }
          }
        },
        "operator": "crosses_above",
        "rhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 200,
              "source": "close"
            }
          }
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "golden_cross"
    }
  },
  "exit_signal": {
    "rules": [
      {
        "id": "death_cross",
        "lhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 50,
              "source": "close"
            }
          }
        },
        "operator": "crosses_below",
        "rhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 200,
              "source": "close"
            }
          }
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "death_cross"
    }
  }
}
该示例展示了规则ID和
exit_signal
的标准用法。
json
{
  "symbol": "BTC-USD",
  "timeframe": "daily",
  "start_at": "2020-01-01",
  "initial_capital": 100000,
  "execution": {
    "side": "long",
    "entry_mode": "next_bar_open"
  },
  "entry": {
    "rules": [
      {
        "id": "golden_cross",
        "lhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 50,
              "source": "close"
            }
          }
        },
        "operator": "crosses_above",
        "rhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 200,
              "source": "close"
            }
          }
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "golden_cross"
    }
  },
  "exit_signal": {
    "rules": [
      {
        "id": "death_cross",
        "lhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 50,
              "source": "close"
            }
          }
        },
        "operator": "crosses_below",
        "rhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 200,
              "source": "close"
            }
          }
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "death_cross"
    }
  }
}

2. Mean Reversion: RSI Oversold Bounce

2. 均值回归:RSI超卖反弹

Good example for scalar thresholds plus
stop_loss
and
take_profit
.
json
{
  "symbol": "AAPL",
  "timeframe": "daily",
  "start_at": "2020-01-01",
  "initial_capital": 100000,
  "execution": {
    "side": "long",
    "entry_mode": "next_bar_open"
  },
  "entry": {
    "rules": [
      {
        "id": "rsi_oversold",
        "lhs": {
          "indicator": {
            "key": "rsi",
            "params": {
              "period": 14,
              "source": "close"
            }
          }
        },
        "operator": "lte",
        "rhs": {
          "value": 30
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "rsi_oversold"
    }
  },
  "exits": {
    "stop_loss": {
      "mode": "percent",
      "value": 5
    },
    "take_profit": {
      "mode": "percent",
      "value": 10
    },
    "max_hold_bars": 20
  }
}
该示例展示了标量阈值结合
stop_loss
take_profit
的用法。
json
{
  "symbol": "AAPL",
  "timeframe": "daily",
  "start_at": "2020-01-01",
  "initial_capital": 100000,
  "execution": {
    "side": "long",
    "entry_mode": "next_bar_open"
  },
  "entry": {
    "rules": [
      {
        "id": "rsi_oversold",
        "lhs": {
          "indicator": {
            "key": "rsi",
            "params": {
              "period": 14,
              "source": "close"
            }
          }
        },
        "operator": "lte",
        "rhs": {
          "value": 30
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "rsi_oversold"
    }
  },
  "exits": {
    "stop_loss": {
      "mode": "percent",
      "value": 5
    },
    "take_profit": {
      "mode": "percent",
      "value": 10
    },
    "max_hold_bars": 20
  }
}

3. Trend Breakout: Stop Above 55-Bar High

3. 趋势突破:突破55根K线高点的止损入场

Good example for a more canonical Donchian-style trend-following breakout with a long-term trend filter.
json
{
  "symbol": "BTC-USD",
  "timeframe": "daily",
  "start_at": "2020-01-01",
  "initial_capital": 100000,
  "execution": {
    "side": "long",
    "entry_mode": "next_bar_stop",
    "entry_price": {
      "basis": "highest_high",
      "lookback": 55,
      "offset": {
        "mode": "fixed",
        "value": 0
      }
    }
  },
  "entry": {
    "rules": [
      {
        "id": "above_sma_200",
        "lhs": {
          "field": "close"
        },
        "operator": "gte",
        "rhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 200,
              "source": "close"
            }
          }
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "above_sma_200"
    }
  },
  "exits": {
    "lowest_low_exit_lookback": 20
  }
}
该示例展示了经典Donchian风格的趋势突破策略,结合长期趋势过滤。
json
{
  "symbol": "BTC-USD",
  "timeframe": "daily",
  "start_at": "2020-01-01",
  "initial_capital": 100000,
  "execution": {
    "side": "long",
    "entry_mode": "next_bar_stop",
    "entry_price": {
      "basis": "highest_high",
      "lookback": 55,
      "offset": {
        "mode": "fixed",
        "value": 0
      }
    }
  },
  "entry": {
    "rules": [
      {
        "id": "above_sma_200",
        "lhs": {
          "field": "close"
        },
        "operator": "gte",
        "rhs": {
          "indicator": {
            "key": "sma",
            "params": {
              "period": 200,
              "source": "close"
            }
          }
        }
      }
    ],
    "logic": {
      "type": "rule",
      "id": "above_sma_200"
    }
  },
  "exits": {
    "lowest_low_exit_lookback": 20
  }
}

Curl Reference

Curl参考示例

Use these snippets directly when you need to query or execute against the API.
当你需要查询或调用API时,请直接使用以下代码片段。

Base Variables

基础变量

bash
SEREN_PUBLISHER_BASE_URL="${SEREN_PUBLISHER_BASE_URL:-https://api.serendb.com/publishers/plausibleai}"
SEREN_API_KEY="${SEREN_API_KEY:?Set SEREN_API_KEY}"
Every request uses:
bash
-H "Authorization: Bearer $SEREN_API_KEY"
bash
SEREN_PUBLISHER_BASE_URL="${SEREN_PUBLISHER_BASE_URL:-https://api.serendb.com/publishers/plausibleai}"
SEREN_API_KEY="${SEREN_API_KEY:?Set SEREN_API_KEY}"
所有请求均需携带:
bash
-H "Authorization: Bearer $SEREN_API_KEY"

Market Discovery

市场探索

List market types:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/markets/types" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
Search symbols:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/markets/symbols?market_type=crypto&search=bitcoin&limit=20" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
Get symbol detail:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/markets/symbols/BTC-USD" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
列出市场类型:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/markets/types" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
搜索标的:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/markets/symbols?market_type=crypto&search=bitcoin&limit=20" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
获取标的详情:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/markets/symbols/BTC-USD" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq

DSL Discovery

DSL探索

bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/catalog" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/catalog" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq

Validate a Backtest

验证回测请求

bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/validate" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "symbol": "BTC-USD",
    "timeframe": "daily",
    "start_at": "2020-01-01",
    "initial_capital": 100000,
    "execution": {
      "side": "long",
      "entry_mode": "next_bar_open"
    },
    "entry": {
      "rules": [
        {
          "id": "golden_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_above",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "golden_cross"
      }
    },
    "exit_signal": {
      "rules": [
        {
          "id": "death_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_below",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "death_cross"
      }
    }
  }' | jq
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/validate" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "symbol": "BTC-USD",
    "timeframe": "daily",
    "start_at": "2020-01-01",
    "initial_capital": 100000,
    "execution": {
      "side": "long",
      "entry_mode": "next_bar_open"
    },
    "entry": {
      "rules": [
        {
          "id": "golden_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_above",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "golden_cross"
      }
    },
    "exit_signal": {
      "rules": [
        {
          "id": "death_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_below",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "death_cross"
      }
    }
  }' | jq

Execute a Backtest

执行回测

bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "symbol": "BTC-USD",
    "timeframe": "daily",
    "start_at": "2020-01-01",
    "initial_capital": 100000,
    "execution": {
      "side": "long",
      "entry_mode": "next_bar_open"
    },
    "entry": {
      "rules": [
        {
          "id": "golden_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_above",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "golden_cross"
      }
    },
    "exit_signal": {
      "rules": [
        {
          "id": "death_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_below",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "death_cross"
      }
    }
  }' | jq
The response from
POST /api/backtests
is a compact stored-result summary. Use the returned
id
or
links.full_result_path
to fetch the full backtest result when needed.
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "symbol": "BTC-USD",
    "timeframe": "daily",
    "start_at": "2020-01-01",
    "initial_capital": 100000,
    "execution": {
      "side": "long",
      "entry_mode": "next_bar_open"
    },
    "entry": {
      "rules": [
        {
          "id": "golden_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_above",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "golden_cross"
      }
    },
    "exit_signal": {
      "rules": [
        {
          "id": "death_cross",
          "lhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 50,
                "source": "close"
              }
            }
          },
          "operator": "crosses_below",
          "rhs": {
            "indicator": {
              "key": "sma",
              "params": {
                "period": 200,
                "source": "close"
              }
            }
          }
        }
      ],
      "logic": {
        "type": "rule",
        "id": "death_cross"
      }
    }
  }' | jq
POST /api/backtests
接口的响应为简洁的存储结果摘要。当需要获取完整回测结果时,可使用返回的
id
links.full_result_path

Retrieve a Stored Backtest Result

检索存储的回测结果

Use the
id
returned in the compact response from
POST /api/backtests
or
POST /api/backtests/mine
.
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
Retrieve all trades:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/trades" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
Retrieve paginated trades when needed:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/trades?limit=100&offset=0" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
Retrieve the full equity curve:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/equity-curve" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
Retrieve paginated equity curve when needed:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/equity-curve?limit=100&offset=0" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
使用
POST /api/backtests
POST /api/backtests/mine
接口返回的简洁响应中的
id
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
获取所有交易记录:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/trades" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
当需要分页时,获取分页交易记录:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/trades?limit=100&offset=0" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
获取完整权益曲线:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/equity-curve" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq
当需要分页时,获取分页权益曲线:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/<BACKTEST_ID>/equity-curve?limit=100&offset=0" \
  -H "Authorization: Bearer $SEREN_API_KEY" | jq

Mine an Actionable Strategy

挖掘可执行策略

Minimal mining request:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/mine" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "symbol": "BTC-USD"
  }' | jq
Mining returns:
  • symbol
  • signal_at
  • fitness_metric
  • fitness_value
  • mined_candidates
  • actionable_candidates
  • rank
  • backtest
backtest
contains the stored result handle and compact summary:
  • id
  • kind
  • created_at
  • expires_at
  • request
  • summary
  • links.full_result_path
  • links.trades_path
  • links.equity_curve_path
最简挖掘请求:
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/mine" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "symbol": "BTC-USD"
  }' | jq
挖掘接口返回以下内容:
  • symbol
  • signal_at
  • fitness_metric
  • fitness_value
  • mined_candidates
  • actionable_candidates
  • rank
  • backtest
backtest
字段包含存储结果句柄和简洁摘要:
  • id
  • kind
  • created_at
  • expires_at
  • request
  • summary
  • links.full_result_path
  • links.trades_path
  • links.equity_curve_path

Batch Execution

批量执行

bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/batch" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "requests": [
      {
        "symbol": "BTC-USD",
        "timeframe": "daily",
        "start_at": "2020-01-01",
        "initial_capital": 100000,
        "execution": {
          "side": "long",
          "entry_mode": "next_bar_open"
        },
        "entry": {
          "rules": [
            {
              "id": "golden_cross",
              "lhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 50,
                    "source": "close"
                  }
                }
              },
              "operator": "crosses_above",
              "rhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 200,
                    "source": "close"
                  }
                }
              }
            }
          ],
          "logic": {
            "type": "rule",
            "id": "golden_cross"
          }
        },
        "exit_signal": {
          "rules": [
            {
              "id": "death_cross",
              "lhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 50,
                    "source": "close"
                  }
                }
              },
              "operator": "crosses_below",
              "rhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 200,
                    "source": "close"
                  }
                }
              }
            }
          ],
          "logic": {
            "type": "rule",
            "id": "death_cross"
          }
        }
      }
    ]
  }' | jq
bash
curl -sS "$SEREN_PUBLISHER_BASE_URL/api/backtests/batch" \
  -H "Authorization: Bearer $SEREN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "requests": [
      {
        "symbol": "BTC-USD",
        "timeframe": "daily",
        "start_at": "2020-01-01",
        "initial_capital": 100000,
        "execution": {
          "side": "long",
          "entry_mode": "next_bar_open"
        },
        "entry": {
          "rules": [
            {
              "id": "golden_cross",
              "lhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 50,
                    "source": "close"
                  }
                }
              },
              "operator": "crosses_above",
              "rhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 200,
                    "source": "close"
                  }
                }
              }
            }
          ],
          "logic": {
            "type": "rule",
            "id": "golden_cross"
          }
        },
        "exit_signal": {
          "rules": [
            {
              "id": "death_cross",
              "lhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 50,
                    "source": "close"
                  }
                }
              },
              "operator": "crosses_below",
              "rhs": {
                "indicator": {
                  "key": "sma",
                  "params": {
                    "period": 200,
                    "source": "close"
                  }
                }
              }
            }
          ],
          "logic": {
            "type": "rule",
            "id": "death_cross"
          }
        }
      }
    ]
  }' | jq

DSL Rules

DSL规则

  • Keep rule ids short and stable. Use letters, numbers, underscores, or hyphens only.
  • Use
    bars_ago
    on
    lhs
    or
    rhs
    when you need to compare against an earlier bar. Omit it for the current bar.
  • Use
    crosses_above
    and
    crosses_below
    only when prior-bar behavior is intended.
  • Prefer
    gte
    or
    lte
    over
    eq
    or
    ne
    for floating-point comparisons.
  • Remember that
    xor
    uses parity semantics: it is true when an odd number of child nodes are true.
  • catalog.limits.max_bars_ago
    is the maximum allowed
    bars_ago
    value.
  • The
    atr
    indicator only accepts
    period
    . Passing
    source
    to
    atr
    is a validation error.
  • Indicator
    period
    params are always required. The catalog lists no default value for them; omitting
    period
    returns a 422.
  • Add
    "negate": true
    to any rule to invert its signal (fires when the condition is NOT met). Cannot be combined with
    crosses_above
    or
    crosses_below
    — use the complementary operator instead. For compound negation, apply
    negate
    to individual rules and combine with
    any
    /
    all
    logic nodes using De Morgan's laws.
  • 保持规则ID简短且稳定。仅可使用字母、数字、下划线或连字符。
  • 当需要与之前的K线进行比较时,在
    lhs
    rhs
    中使用
    bars_ago
    参数。当前K线无需使用该参数。
  • 仅当需要参考前一根K线的行为时,使用
    crosses_above
    crosses_below
    运算符。
  • 对于浮点数比较,优先使用
    gte
    lte
    而非
    eq
    ne
  • 请注意
    xor
    运算符使用奇偶语义:当子节点中奇数个为真时,结果为真。
  • catalog.limits.max_bars_ago
    bars_ago
    参数的最大允许值。
  • atr
    指标仅接受
    period
    参数。为
    atr
    传递
    source
    参数会触发验证错误。
  • 指标的
    period
    参数始终为必填项。目录中未为其设置默认值;省略
    period
    参数会返回422错误。
  • 可为任意规则添加
    "negate": true
    来反转其信号(当条件不满足时触发)。该参数无法与
    crosses_above
    crosses_below
    运算符组合使用——请改用对应的互补运算符。对于复合否定,请为单个规则应用
    negate
    参数,并使用德摩根定律通过
    any
    /
    all
    逻辑节点组合。

Common Pitfalls

常见误区

MistakeFix
Omitting
id
on a rule
Every rule in
rules[]
must have a unique
id
; logic nodes reference it
Guessing indicator defaultsAlways provide
period
; there is no server default
Passing
source
to
atr
ATR does not accept source; use
period
only
Using
eq
/
ne
on float indicators
Use
gte
/
lte
range checks instead
crosses_above
with too little data
Cross operators need one additional prior bar beyond the indicator lookback
"negate": true
with
crosses_above
/
crosses_below
Not allowed — cross operators fire on a single bar; their negation fires on ~99% of bars. Use the complementary operator instead
af_step > af_max
on
parabolic_sar
Validation error — step must be ≤ max
short_period >= long_period
on
tsi
Validation error — short must be < long
exit_signal
and
exits
both provided
Both are valid simultaneously;
exits
handles price levels,
exit_signal
handles rule-based signals
entry_price
with
next_bar_open
entry_price
only works with
next_bar_limit
or
next_bar_stop
Logic node referencing undefined idLogic node
id
must exactly match a rule
id
in the same
rules[]
array
No signals firingCheck
diagnostics.entry.rules[]
per-rule signal counts; adjust lookback, threshold, or date range
错误操作修复方案
规则中省略
id
rules[]
中的每个规则都必须包含唯一的
id
;逻辑节点通过该ID引用规则
猜测指标的默认值始终显式指定
period
参数;服务器不会为其设置默认值
atr
传递
source
参数
ATR指标不接受source参数;仅需传递
period
参数
对浮点型指标使用
eq
/
ne
运算符
使用
gte
/
lte
进行范围比较
使用
crosses_above
时数据量不足
交叉运算符需要比指标回溯周期多一根K线的数据
crosses_above
/
crosses_below
设置
"negate": true
该操作不被允许——交叉运算符仅在单根K线触发;其否定形式会在约99%的K线触发。请改用对应的互补运算符
parabolic_sar
af_step > af_max
该配置会触发验证错误——步长必须小于等于最大值
tsi
short_period >= long_period
该配置会触发验证错误——短期周期必须小于长期周期
同时提供
exit_signal
exits
参数
两者可同时生效;
exits
处理价格水平离场,
exit_signal
处理基于规则的信号离场
next_bar_open
模式下使用
entry_price
entry_price
仅在
next_bar_limit
next_bar_stop
模式下有效
逻辑节点引用未定义的ID逻辑节点的
id
必须与同一
rules[]
数组中的某个规则ID完全匹配
无信号触发查看
diagnostics.entry.rules[]
中的单规则信号计数;调整回溯周期、阈值或日期范围

Response Discipline

响应规范

  • Prefer returning concise summaries unless the user asks for raw JSON.
  • POST /api/backtests
    and
    POST /api/backtests/mine
    both return compact stored-result summaries first; do not assume the full backtest payload is in the initial response.
  • For stored results, summarize the compact summary first and only fetch the full result,
    trades
    , or
    equity_curve
    when the user needs that detail.
  • Use
    ?limit=&offset=
    for
    trades
    or
    equity_curve
    only when the result is large enough that incremental retrieval is useful.
  • When showing example payloads, include rule ids explicitly.
  • When the symbol is uncertain, use the market endpoints first instead of inventing tickers.
  • When a backtest output looks surprising, compare
    trades
    ,
    equity_curve
    , and
    diagnostics
    before assuming the engine is wrong.
  • 除非用户明确要求原始JSON,否则优先返回简洁摘要。
  • POST /api/backtests
    POST /api/backtests/mine
    接口均先返回简洁的存储结果摘要;请勿假设初始响应中包含完整回测负载。
  • 对于存储的结果,先展示简洁摘要;仅当用户需要详细内容时,再获取完整结果、
    trades
    equity_curve
  • 仅当结果集大到需要增量检索时,才为
    trades
    equity_curve
    添加
    ?limit=&offset=
    参数。
  • 展示请求示例时,请显式包含规则ID。
  • 当标的不确定时,先使用市场端点查询,而非自行编造代码。
  • 当回测结果看起来异常时,请先对比
    trades
    equity_curve
    diagnostics
    字段,再假设引擎存在错误。