跳到主要内容

信号原语参考指南

信号原语(Signal Primitives)是用于生成交易信号的组件,它们接收一个或多个时间序列作为输入,并输出布尔型时间序列(true/false)。这些组件可以组合成复杂的交易条件。

信号原语基础

所有信号原语都实现了evaluate方法,该方法接收输入时间序列并返回布尔结果。信号原语可以:

  1. 评估单个时间点(返回单个布尔值)
  2. 评估整个时间序列(返回布尔型Series)

可用信号原语

比较类信号

⚠️ 重要警告:输入顺序至关重要

对于所有比较类信号(尤其是LessThan和GreaterThan),输入参数的顺序会直接影响比较结果。 当涉及常量与变量的比较时,必须将常量放在左侧,变量放在右侧,以确保执行预期的比较。

错误示例(常见错误!):

// 本意是 rsi < 70,但实际执行的是 70 < rsi
{
"type": "LessThan",
"inputs": [
{ "ref": "rsi" },
{ "type": "Constant", "value": 70 }
]
}

正确示例:

// 正确执行 rsi < 70
{
"type": "LessThan",
"inputs": [
{ "type": "Constant", "value": 70 },
{ "ref": "rsi" }
]
}

GreaterThan 和 LessThan (替代 Comparison)

推荐使用 GreaterThan 和 LessThan 替代通用的 Comparison,它们提供更明确的语义和更好的性能。

{
"id": "price_above_ma",
"type": "GreaterThan",
"epsilon": 0.01,
"inputs": [
{ "column": "Close" },
{ "ref": "ma_indicator" }
]
}

参数:

  • epsilon: 用于处理浮点比较精度问题的小值(默认: 0)

注意事项:

  • 比较两个时间序列时,会使用epsilon值作为精度缓冲
  • 输入顺序至关重要,请参考下面的 GreaterThan 和 LessThan 部分

GreaterThan (大于)

检查第一个输入是否大于第二个输入。输入顺序至关重要

{
"id": "price_gt_ma",
"type": "GreaterThan",
"epsilon": 0.01,
"inputs": [
{ "column": "Close" }, // 要检查的值放第一位
{ "ref": "ma_indicator" } // 与之比较的值放第二位
]
}

常量比较的正确写法

{
"id": "rsi_overbought",
"type": "GreaterThan",
"epsilon": 0.5,
"inputs": [
{ "ref": "rsi_indicator" }, // 变量放第一位
{ "ref": "upper_threshold" } // 引用常量指标而不是直接使用value
]
}

参数:

  • epsilon: 浮点数比较精度参数(可选,默认为0)。当比较 a > b 时,实际比较为 a > (b + epsilon)。
    • 例如:当阈值为70,epsilon为0.01时,只有值大于70.01才会返回true
    • 适用于处理边界条件和浮点数精度问题

注意事项

  • 无论是否使用 epsilon,输入的顺序都是决定性的
  • 对于 GreaterThan(a, b),执行的是 a > (b + epsilon)
  • 推荐使用常量指标(如 upper_threshold)而不是直接使用 value 属性

LessThan (小于)

检查第一个输入是否小于第二个输入。输入顺序至关重要

{
"id": "price_lt_ma",
"type": "LessThan",
"epsilon": 0.01,
"inputs": [
{ "column": "Close" }, // 要检查的值放第一位
{ "ref": "ma_indicator" } // 与之比较的值放第二位
]
}

常量比较的正确写法

{
"id": "rsi_not_overbought",
"type": "LessThan",
"epsilon": 0.5,
"inputs": [
{ "ref": "rsi_indicator" }, // 变量放第一位
{ "ref": "upper_threshold" } // 引用常量指标而不是直接使用value
]
}

参数:

  • epsilon: 浮点数比较精度参数(可选,默认为0)。当比较 a < b 时,实际比较为 a < (b - epsilon)。
    • 例如:当阈值为70,epsilon为0.01时,只有值小于69.99才会返回true
    • 适用于处理RSI等指标的边界条件和浮点数精度问题

注意事项

  • 无论是否使用 epsilon,输入的顺序都是决定性的
  • 对于 LessThan(a, b),执行的是 a < (b - epsilon)
  • 推荐使用常量指标(如 lower_threshold)而不是直接使用 value 属性

InRange (在范围内)

检查输入值是否在指定范围内。

{
"id": "rsi_neutral",
"type": "InRange",
"params": {
"lower_inclusive": true,
"upper_inclusive": true
},
"inputs": [
{ "ref": "rsi_indicator" },
{ "ref": "lower_bound" },
{ "ref": "upper_bound" }
]
}

参数:

  • lower_inclusive: 是否包含下界(默认: true)
  • upper_inclusive: 是否包含上界(默认: true)

注意事项:

  • 需要三个输入: 评估值, 下界, 上界
  • 适合检测指标是否在特定区间内(如RSI在30-70之间)

交叉类信号

Crossover (上穿)

检测第一个输入是否向上穿越第二个输入。

{
"id": "price_cross_above_ma",
"type": "Crossover",
"params": { "mode": "simple" },
"inputs": [
{ "column": "Close" },
{ "ref": "ma_indicator" }
]
}

参数:

  • mode: 交叉检测模式,可选值:
    • simple: 简单交叉检测(默认)
    • confirmed: 要求确认(连续两个周期)

注意事项:

  • 只在实际发生穿越的那一个时间点返回true
  • 穿越后的后续时间点返回false,直到发生新的穿越
  • 适合用作买入/卖出触发信号

Crossunder (下穿)

检测第一个输入是否向下穿越第二个输入。

{
"id": "price_cross_below_ma",
"type": "Crossunder",
"params": { "mode": "simple" },
"inputs": [
{ "column": "Close" },
{ "ref": "ma_indicator" }
]
}

参数:

  • mode: 交叉检测模式,可选值:
    • simple: 简单交叉检测(默认)
    • confirmed: 要求确认(连续两个周期)

注意事项:

  • 只在实际发生穿越的那一个时间点返回true
  • 穿越后的后续时间点返回false,直到发生新的穿越
  • 适合用作买入/卖出触发信号

逻辑运算符类

And (逻辑与)

要求所有输入信号同时为true。支持嵌套信号和内联常量。

基本用法

{
"id": "buy_condition",
"type": "And",
"inputs": [
{ "ref": "price_above_ma" },
{ "ref": "rsi_oversold" }
]
}

嵌套信号示例

{
"id": "buy_condition_core",
"type": "And",
"inputs": [
{ "ref": "macd_cross_signal" },
{
"type": "GreaterThan",
"inputs": [
{ "column": "Volume" },
{ "ref": "volume_ma" }
],
"params": {
"threshold": 1.5
}
}
]
}

内联常量支持

{
"id": "enhanced_buy",
"type": "And",
"inputs": [
{ "ref": "buy_condition_core" },
{
"type": "LessThan",
"inputs": [
{ "ref": "volume_ratio" },
{ "type": "Constant", "value": 3 }
]
}
]
}

Or (逻辑或)

当任一输入信号为true时返回true。

{
"id": "sell_condition",
"type": "Or",
"inputs": [
{ "ref": "stop_loss_hit" },
{ "ref": "take_profit_hit" }
]
}

Not (逻辑非)

对输入信号取反。

{
"id": "not_overbought",
"type": "Not",
"inputs": [
{ "ref": "rsi_overbought" }
]
}

逻辑运算符新特性

  1. 嵌套信号支持: And/Or可以接受嵌套的信号定义作为输入
  2. 内联常量: 嵌套信号中支持 {"type": "Constant", "value": N} 格式
  3. 灵活组合: 可以混合使用信号引用和嵌套定义

注意事项:

  • 增强了NaN处理逻辑
  • 适合需要排除特定条件的场景
  • 嵌套信号会自动评估,无需预先定义ID

模式识别类

Streak (连续模式)

检测连续满足条件的模式。注意:Streak 使用"回溯标记"语义,即标记整个符合条件的连续序列,而非延迟触发。

{
"id": "consecutive_up_days",
"type": "Streak",
"params": {
"match_type": "true",
"min_length": 3,
"max_length": 5
},
"inputs": [
{ "ref": "daily_gain" }
]
}

参数:

  • match_type: 匹配类型,可选值:
    • "true" (默认): 检测连续的 True 值
    • "false": 检测连续的 False 值
    • "any": 检测任意连续相同的值(不区分 True/False)
  • min_length: 最小连续长度(默认: 2,必须大于0)
  • max_length: 最大连续长度(可选,如指定则必须大于等于min_length)

行为说明:

Streak 采用"回溯标记"(retrospective marking)语义:

  1. 整序列标记: 当检测到符合条件的连续序列时,会标记该序列中的所有位置(从第一天开始),而非仅标记第 N 天
  2. max_length 截断: 如果连续序列超过 max_length,只标记前 max_length 个位置
  3. 批量处理: 作为无状态原语,Streak 一次性处理整个时间序列

示例:

假设输入序列为 [F, T, T, T, T, F],配置 min_length=3, max_length=null, match_type="true"

  • 结果: [F, T, T, T, T, F] — 标记所有 4 个连续 True 位置

假设输入序列为 [F, T, T, T, T, T, F],配置 min_length=3, max_length=3

  • 结果: [F, T, T, T, F, F, F] — 只标记前 3 个位置

注意事项:

  • 适合检测连续上涨/下跌或其他持续模式
  • 不适合用于"等待 N 天后再触发"的延迟信号场景(因为是回溯标记而非延迟触发)
  • 如需延迟触发语义,请使用 Lag 原语组合实现(见下文)

时序类

Lag (时序位移)

将时间序列按指定周期位移,用于实现延迟确认、历史数据引用等场景。这是实现"连续 N 天确认后触发"逻辑的核心原语。

{
"id": "yesterday_condition",
"type": "Lag",
"params": {
"periods": 1,
"fill_value": 0
},
"inputs": [
{ "ref": "today_condition" }
]
}

参数:

  • periods: 位移周期数(默认: 1,大于等于0)。正数表示向后看(获取过去的值)
  • fill_value: 填充值(可选)。位移产生的空值用此填充。布尔序列建议用 0 (False) 或 1 (True)

典型用法 - 连续 2 天确认:

{
"signals": [
{
"id": "condition_today",
"type": "LessThan",
"inputs": [
{ "ref": "some_indicator" },
{ "ref": "threshold" }
]
},
{
"id": "condition_yesterday",
"type": "Lag",
"params": { "periods": 1, "fill_value": 0 },
"inputs": [{ "ref": "condition_today" }]
},
{
"id": "confirmed_signal",
"type": "And",
"inputs": [
{ "ref": "condition_today" },
{ "ref": "condition_yesterday" }
]
}
]
}

执行逻辑:

日期        condition_today  condition_yesterday  confirmed_signal
Day 1 True False (filled) False ← 第1天不触发
Day 2 True True (from Day1) True ← 连续2天,触发!
Day 3 True True (from Day2) True
Day 4 False True (from Day3) False

注意事项:

  • Lag 是无状态原语,符合声明式配置的设计原则
  • And 组合可实现任意 N 天确认逻辑
  • fill_value 对于布尔信号很重要,建议显式设置为 0

数学运算类

🆕 新功能:纯数学运算模式

数学运算类信号现在支持两种工作模式:

  1. 比较模式(默认):执行数学运算后与阈值比较,返回布尔结果
  2. 纯数学模式:设置 return_calculation=true 时,直接返回数学运算结果

PercentChange (百分比变化)

计算时间序列的百分比变化,并与阈值或另一时间序列比较。

{
"id": "price_up_5percent",
"type": "PercentChange",
"params": {
"period": 5,
"threshold": 5.0,
"comparison": "greater"
},
"inputs": [
{ "column": "Close" }
]
}

参数:

  • period: 计算变化的周期(默认: 1)
  • threshold: 比较阈值(可选)
  • comparison: 比较类型(默认: "greater")

注意事项:

  • 可与阈值比较或与另一时间序列比较
  • 适合检测价格动量或大幅波动

Add (加法)

将两个或多个时间序列相加。支持比较模式和纯数学运算模式。

比较模式示例(默认行为):

{
"id": "combined_gt_threshold",
"type": "Add",
"params": {
"threshold": 100,
"comparison": "greater"
},
"inputs": [
{ "ref": "indicator1" },
{ "ref": "indicator2" }
]
}

纯数学运算模式示例

{
"id": "combined_indicator",
"type": "Add",
"params": {
"return_calculation": true
},
"inputs": [
{ "ref": "indicator1" },
{ "ref": "indicator2" },
{ "ref": "indicator3" }
]
}

参数:

  • return_calculation: 是否返回计算结果而非比较结果(默认: false)
  • threshold: 比较阈值(仅在比较模式下使用)
  • comparison: 比较类型(仅在比较模式下使用,默认: "greater")
  • absolute: 是否对结果取绝对值(默认: false) 内联常量支持
{
"id": "indicator_plus_constant",
"type": "Add",
"params": {
"return_calculation": true
},
"inputs": [
{ "ref": "base_indicator" },
{ "type": "Constant", "value": 10 }
]
}

Subtract (减法)

从第一个时间序列中减去第二个及后续时间序列(按从左到右顺序)。

纯数学运算示例

{
"id": "indicator_difference",
"type": "Subtract",
"params": {
"return_calculation": true
},
"inputs": [
{ "ref": "indicator1" },
{ "ref": "indicator2" }
]
}

多操作数示例(左到右计算:(a - b) - c):

{
"id": "sequential_subtract",
"type": "Subtract",
"params": {
"return_calculation": true
},
"inputs": [
{ "ref": "base_value" },
{ "ref": "adjustment1" },
{ "type": "Constant", "value": 5 }
]
}

Multiply (乘法)

将两个或多个时间序列相乘(支持多操作数)。

纯数学运算示例

{
"id": "weighted_indicator",
"type": "Multiply",
"params": {
"return_calculation": true
},
"inputs": [
{ "ref": "indicator" },
{ "ref": "weight" }
]
}

多操作数乘法示例

{
"id": "signal_strength",
"type": "Multiply",
"params": {
"return_calculation": true
},
"inputs": [
{ "ref": "macd_atr_ratio" },
{ "ref": "ma_close_ratio" },
{ "type": "Constant", "value": 1.0 }
]
}

Divide (除法)

将第一个时间序列除以第二个及后续时间序列(按从左到右顺序)。

纯数学运算示例

{
"id": "indicator_ratio",
"type": "Divide",
"params": {
"return_calculation": true
},
"inputs": [
{ "ref": "indicator1" },
{ "ref": "indicator2" }
]
}

多操作数示例(左到右计算:(a / b) / c):

{
"id": "normalized_ratio",
"type": "Divide",
"params": {
"return_calculation": true
},
"inputs": [
{ "column": "Volume" },
{ "ref": "volume_ma" },
{ "type": "Constant", "value": 1000 }
]
}

数学运算类通用参数

  • return_calculation: 是否返回纯数学计算结果(默认: false)
    • true: 返回数值结果,支持多操作数按从左到右计算
    • false: 执行运算后与阈值比较,返回布尔结果
  • threshold: 比较阈值(仅在比较模式下生效)
  • comparison: 比较类型("greater", "less", "equal"等,仅在比较模式下生效)
  • absolute: 是否对运算结果取绝对值(默认: false) 重要特性
  1. 向后兼容: 默认行为保持不变,现有配置无需修改
  2. 多操作数支持: 纯数学模式支持2个以上输入,按从左到右顺序计算
  3. 内联常量: 支持 {"type": "Constant", "value": N} 格式的内联常量
  4. 除零处理: Divide操作自动处理除零情况,返回NaN

策略切换类

StockBondSwitch (股债切换)

⚠️ 智能资产轮动信号

这是一个专门为多资产轮动策略设计的智能信号原语,它能够自动识别当前正在评估的标的, 并根据标的在投资组合中的位置(约定:第一个=股票类资产,第二个=债券类资产)以及市场条件 返回相应的买入信号。

根据市场条件信号为不同资产生成互补的买入信号,实现股债轮动策略。

{
"id": "stock_bond_buy",
"type": "StockBondSwitch",
"params": {
"default_to_stock": true
},
"inputs": [
{ "ref": "market_trend_up" }
]
}

工作原理:

该原语能够智能识别当前正在评估的标的和投资组合中的所有标的, 根据标的在投资组合中的位置和市场条件,为不同标的返回互补的买入信号:

条件信号股票ETF(位置0)债券ETF(位置1)
TrueTrue (买入)False (不买)
FalseFalse (不买)True (买入)

配置约定:

  • symbols[0]: 股票ETF(如510300、SPY等)
  • symbols[1]: 债券ETF(如511260、TLT等)

参数:

  • default_to_stock: 当条件信号中包含NaN值时的默认填充行为(默认: true)
    • true: NaN填充为True(偏向股票)
    • false: NaN填充为False(偏向债券)

返回值:

  • 返回布尔型 pd.Series,表示当前标的是否应该买入
  • 对于股票ETF:条件为True时返回True,条件为False时返回False
  • 对于债券ETF:条件为False时返回True,条件为True时返回False

完整配置示例:

{
"market_indicators": {
"indicators": [
{
"code": "000300.SH"
}
],
"transformers": [
{
"name": "hs300_raw",
"type": "IdentityTransformer",
"params": {
"indicator": "000300.SH",
"field": "Close"
}
},
{
"name": "hs300_ma200",
"type": "MovingAverageTransformer",
"params": {
"indicator": "000300.SH",
"window": 200,
"method": "simple",
"field": "Close"
}
}
]
},
"trade_strategy": {
"indicators": [],
"signals": [
{
"id": "market_trend_up",
"type": "GreaterThan",
"inputs": [
{
"market": "000300.SH",
"transformer": "hs300_raw"
},
{
"market": "000300.SH",
"transformer": "hs300_ma200"
}
]
},
{
"id": "stock_bond_buy",
"type": "StockBondSwitch",
"params": {
"default_to_stock": true
},
"inputs": [
{
"ref": "market_trend_up"
}
]
},
{
"id": "stock_bond_sell",
"type": "Not",
"inputs": [
{
"ref": "stock_bond_buy"
}
]
}
],
"outputs": {
"buy_signal": "stock_bond_buy",
"sell_signal": "stock_bond_sell"
}
}
}

技术特点:

  1. 智能识别: 自动识别当前正在评估的标的和投资组合配置

  2. 上下文感知: 能够获取完整的投资组合标的列表和当前标的信息

  3. 安全机制:

    • 无法获取投资组合信息时默认不产生买入信号
    • 投资组合标的少于2个时不产生买入信号
    • 当前标的不在前两个位置时不产生买入信号

注意事项:

  • 这是一个标准的信号原语,返回布尔型Series,与其他信号原语完全兼容
  • 必须配合 CompositeStrategy 使用,不能用于单标的策略
  • 卖出信号通常使用 Not 原语对买入信号取反
  • 适用于任何两资产轮动策略(不仅限于股债)

使用场景:

  • 股债轮动(股票ETF ↔ 债券ETF)
  • 风险开关策略(风险资产 ↔ 避险资产)
  • 趋势跟踪(趋势资产 ↔ 现金等价物)
  • 动量轮动(高动量资产 ↔ 低动量资产)

权重控制原语

权重控制原语用于动态调整仓位大小,输出 0.0-1.0 之间的目标权重值。这些原语与交易信号配合使用,实现基于市场条件的灵活仓位管理。

核心概念

target_weight(目标权重):表示某个标的应占总资产的目标比例,取值范围 0.0-1.0。

  • 0.0:空仓(完全不持有)
  • 0.3:轻仓(持有30%)
  • 0.6:中仓(持有60%)
  • 1.0:满仓(全仓持有)

执行语义

重要理解target_weight 表示在交易信号触发时使用的目标权重,而非实时维护的目标权重:

  • 买入信号(B)触发时:按 target_weight 建仓
  • 卖出信号(S)触发且 target_weight > 0 时:调整到 target_weight(部分卖出)
  • 持有期间(H) target_weight 变化:不触发自动调整

设计理由

  1. 避免因指标波动产生过度交易
  2. 职责分离:信号控制时机,权重控制规模
  3. 符合主动策略的标准实践

ConditionalWeight (条件权重)

根据布尔条件选择不同的目标权重(离散权重调整)。

{
"id": "rsi_based_weight",
"type": "ConditionalWeight",
"inputs": [
{ "ref": "rsi_overbought" }
],
"params": {
"true_weight": 0.5,
"false_weight": 1.0
}
}

参数:

  • true_weight: 条件为 true 时的目标权重,范围 [0, 1]
  • false_weight: 条件为 false 时的目标权重,范围 [0, 1]

输入:

  • 单个布尔条件序列 (pd.Series of bool)

输出:

  • 权重序列 (pd.Series of float),值为 true_weightfalse_weight

使用场景:

  • RSI超买超卖调仓:RSI > 70 时半仓,RSI 正常时满仓
  • PE/PB估值调仓:估值过高时减仓,估值正常时满仓
  • 波动率调仓:高波动时减仓,低波动时加仓
  • 任何基于条件的离散权重调整

完整示例:

{
"indicators": [
{
"id": "rsi",
"type": "RSI",
"params": { "period": 14 }
},
{
"id": "sma_short",
"type": "SMA",
"params": { "period": 20 }
},
{
"id": "sma_long",
"type": "SMA",
"params": { "period": 60 }
}
],
"signals": [
{
"id": "rsi_overbought",
"type": "GreaterThan",
"inputs": [
{ "ref": "rsi" },
{ "type": "Constant", "value": 70 }
]
},
{
"id": "buy_signal",
"type": "CrossAbove",
"inputs": [
{ "ref": "sma_short" },
{ "ref": "sma_long" }
]
},
{
"id": "sell_signal",
"type": "CrossBelow",
"inputs": [
{ "ref": "sma_short" },
{ "ref": "sma_long" }
]
},
{
"id": "dynamic_weight",
"type": "ConditionalWeight",
"inputs": [{ "ref": "rsi_overbought" }],
"params": {
"true_weight": 0.5,
"false_weight": 1.0
}
}
],
"outputs": {
"buy_signal": "buy_signal",
"sell_signal": "sell_signal",
"target_weight": "dynamic_weight"
}
}

执行效果:

  • 当 SMA20 上穿 SMA60 触发买入信号时:
    • 如果 RSI > 70(超买):按 50% 仓位建仓
    • 如果 RSI ≤ 70(正常):按 100% 仓位建仓
  • 持有期间 RSI 变化不会触发交易
  • 只有在新的买入/卖出信号触发时,才会使用当时的 target_weight

LinearScaleWeight (线性缩放权重)

将指标值线性映射到权重范围(连续权重调整)。

{
"id": "rsi_smooth_weight",
"type": "LinearScaleWeight",
"inputs": [
{ "ref": "rsi" }
],
"params": {
"min_indicator": 30,
"max_indicator": 70,
"min_weight": 1.0,
"max_weight": 0.3,
"clip": true
}
}

参数:

  • min_indicator: 指标最小值
  • max_indicator: 指标最大值
  • min_weight: 映射到的最小权重,范围 [0, 1]
  • max_weight: 映射到的最大权重,范围 [0, 1]
  • clip: 是否裁剪超出范围的值(默认: true)

输入:

  • 单个数值指标序列 (pd.Series of float)

输出:

  • 权重序列 (pd.Series of float),值在 [min_weight, max_weight] 范围内

映射公式:

当 indicator 在 [min_indicator, max_indicator] 范围内时,权重按以下公式线性映射:

weight = min_weight + (indicator - min_indicator) / (max_indicator - min_indicator) * (max_weight - min_weight)

clip=true 时,超出范围的值会被裁剪到 [min_weight, max_weight]。

使用场景:

  • RSI平滑调仓:RSI 从 30 到 70,仓位从 100% 平滑降到 30%
  • PE估值调仓:PE 从 15 到 30,仓位从 100% 平滑降到 30%
  • 波动率调仓:ATR比率从 0.7 到 1.8,仓位从 100% 平滑降到 30%
  • 任何需要连续调整权重的场景

完整示例:

{
"indicators": [
{ "id": "rsi", "type": "RSI", "params": { "period": 14 } },
{ "id": "sma_short", "type": "SMA", "params": { "period": 20 } },
{ "id": "sma_long", "type": "SMA", "params": { "period": 60 } }
],
"signals": [
{
"id": "buy_signal",
"type": "CrossAbove",
"inputs": [{ "ref": "sma_short" }, { "ref": "sma_long" }]
},
{
"id": "sell_signal",
"type": "CrossBelow",
"inputs": [{ "ref": "sma_short" }, { "ref": "sma_long" }]
},
{
"id": "smooth_weight",
"type": "LinearScaleWeight",
"inputs": [{ "ref": "rsi" }],
"params": {
"min_indicator": 30,
"max_indicator": 70,
"min_weight": 1.0,
"max_weight": 0.3,
"clip": true
}
}
],
"outputs": {
"buy_signal": "buy_signal",
"sell_signal": "sell_signal",
"target_weight": "smooth_weight"
}
}

执行效果:

  • RSI = 30(超卖)→ target_weight = 1.0(满仓)
  • RSI = 50(中性)→ target_weight = 0.65(65%仓位)
  • RSI = 70(超买)→ target_weight = 0.3(30%仓位)

当买入信号触发时,根据当时的 RSI 值决定建仓比例。

权重原语配置要求

使用权重原语时,需要配合 RebalancingCapitalStrategy 资金策略:

{
"capital_strategy": {
"name": "RebalancingCapitalStrategy",
"params": {
"initial_capital": 100000
}
}
}

如果使用其他资金策略(如 PercentCapitalStrategy),target_weight 将被忽略,策略将按照固定比例交易。

应用场景

1. 估值驱动的动态仓位

根据估值指标(PE/PB)动态调整仓位:

{
"id": "pe_weight",
"type": "LinearScaleWeight",
"inputs": [{ "ref": "pe_ratio" }],
"params": {
"min_indicator": 15,
"max_indicator": 30,
"min_weight": 1.0,
"max_weight": 0.3,
"clip": true
}
}

2. 波动率风险控制

根据市场波动率调整风险敞口:

{
"id": "vix_weight",
"type": "LinearScaleWeight",
"inputs": [{ "ref": "vix" }],
"params": {
"min_indicator": 15,
"max_indicator": 30,
"min_weight": 1.0,
"max_weight": 0.3,
"clip": true
}
}

3. 技术指标组合

结合多个权重原语:

{
"signals": [
{
"id": "rsi_weight",
"type": "LinearScaleWeight",
"inputs": [{ "ref": "rsi" }],
"params": {
"min_indicator": 30,
"max_indicator": 70,
"min_weight": 1.0,
"max_weight": 0.4
}
},
{
"id": "atr_weight",
"type": "LinearScaleWeight",
"inputs": [{ "ref": "atr_ratio" }],
"params": {
"min_indicator": 0.7,
"max_indicator": 1.8,
"min_weight": 1.0,
"max_weight": 0.3
}
},
{
"id": "weight_sum",
"type": "Add",
"params": { "return_calculation": true },
"inputs": [{ "ref": "rsi_weight" }, { "ref": "atr_weight" }]
},
{
"id": "combined_weight",
"type": "Multiply",
"params": { "return_calculation": true },
"inputs": [
{ "ref": "weight_sum" },
{ "type": "Constant", "value": 0.5 }
]
}
],
"outputs": {
"buy_signal": "buy_condition",
"sell_signal": "sell_condition",
"target_weight": "combined_weight"
}
}

相关资源

信号组合最佳实践

  1. 构建复合条件:

    • 使用AndOr组合多个信号
    • 使用Not反转信号
    • 例如: And(CrossAbove(RSI, 30), GreaterThan(Close, SMA))
  2. 交叉事件vs状态:

    • 交叉事件(CrossAbove/CrossBelow)只在穿越发生时为true
    • 状态比较(GreaterThan/LessThan)只要条件满足就一直为true
    • 明确了解这一区别对避免频繁交易很重要
  3. 过滤假信号:

    • 使用Streak要求信号持续一定时间
    • 结合多个指标确认信号
    • 使用趋势过滤器(如价格高于均线)
  4. 信号命名和组织:

    • 使用清晰的ID命名每个信号组件
    • 从简单到复杂逐步构建信号
    • 先定义基本条件,再组合成复杂条件
  5. 动态仓位控制:

    • 权重原语应该输出到 target_weight 字段
    • 必须配合 RebalancingCapitalStrategy 使用
    • 考虑交易成本,避免频繁小幅调仓
    • 权重变化只在交易信号触发时生效

常见错误和解决方案

  1. 过度频繁的信号:

    • 问题: 使用状态比较(如GreaterThan)作为买入信号
    • 解决: 使用CrossAbove/CrossBelow检测交叉事件
  2. 信号缺失:

    • 问题: 输入时间序列有NaN值
    • 解决: 确保指标计算有足够的历史数据
  3. 精度问题:

    • 问题: 浮点比较导致不稳定的结果
    • 解决: 在Comparison中使用epsilon参数
  4. 逻辑错误:

    • 问题: 混淆And/Or逻辑
    • 解决: 仔细验证复合条件的预期行为
  5. 动态仓位不生效:

    • 问题: 使用了 PercentCapitalStrategy 而非 RebalancingCapitalStrategy
    • 解决: 检查资金策略配置,确保使用正确的策略类型
  6. 仓位频繁调整:

    • 问题: 期望 target_weight 变化时自动调仓
    • 解决: 理解执行语义,权重只在交易信号触发时生效