Skip to content

脚本配置界面

当用户点击脚本图例上的 ⚙ 按钮时,图表会推送一个 ConfigureScript(ScriptId) 事件。本页介绍如何使用 ScriptManagement trait 方法构建配置对话框。

ChartView

使用 cv.script_inputs_effective(id) 获取已合并默认值的当前输入。 使用 cv.set_script_config_with_complete(id, config, callback)cv.set_script_config(id, config) 应用更改。

构建配置 UI

本节描述如何为脚本设置构建配置对话框。

配置对话框布局配置对话框布局

对话框结构

对话框包含两个标签页:

标签页内容显示条件
输入脚本 input.*() 参数inputs.len() > 0
视觉序列图视觉覆盖(颜色、样式)graph_configs 非空

如果脚本有输入参数,对话框应默认显示输入标签页,否则显示视觉标签页。

底部按钮:

  • 恢复默认 —— 清除所有覆盖并将输入重置为原始值。
  • 确定 —— 关闭对话框(更改已即时应用,无需确认)。

输入标签页

输入标签页布局输入标签页布局

ConfigureScript 事件提供一个 Vec<InputInfo>

rust
pub struct InputInfo {
    pub idx: usize,                       // 从零开始的输入索引(input_values 的键)
    pub title: Option<String>,            // 人类可读的标签
    pub tooltip: Option<String>,          // 悬停提示文本
    pub group: Option<String>,            // 分组标题(可选)
    pub kind: InputKind,                  // 类型特定的值和约束
    pub default_value: serde_json::Value, // 脚本原始默认值(用于"恢复默认")
}

根据 InputKind 变体渲染每个输入:

Int { value, min, max, step, options } —— 数字输入框。如果 options 非空,显示下拉框而非自由输入。遵循 minmaxstep 约束。

Float { value, min, max, step, options } —— 带小数步长(默认 0.1)的数字输入框。optionsminmax 行为与 Int 相同。

Bool { value } —— 切换开关。

Color { value } —— 色块 + 颜色选择器弹窗。颜色是 RGBA 格式的打包 u32(R << 24) | (G << 16) | (B << 8) | A。显示为填充矩形;点击时打开包含十六进制输入和透明度滑块的颜色选择器。

Str { value, options } —— 文本输入框。如果 options 非空,显示下拉框。

Source { value } —— 固定选项的下拉框:openhighlowclosehl2hlc3ohlc4hlcc4。值为 SourceType 枚举。写入 input_values 时,转换为整数判别值:open=0、high=1、low=2、close=3、hl2=4、hlc3=5、ohlc4=6、hlcc4=7。

Enum { value, options } —— 下拉框。optionsVec<(i64, String)> ——(判别值,显示标签)对。在 input_values 中存储判别值。

Symbol { value } —— 交易标的代码的文本输入框(如 "AAPL")。

TimeFrame { value, options } —— 下拉框或文本输入。值为 TimeFrame。如果 options 非空,显示下拉框。

Session { value, options } —— 交易时段字符串的文本输入框或下拉框(如 "0930-1600")。

Time { value } —— 日期/时间选择器。值为自纪元以来的毫秒数(i64)。使用脚本的交易所时区(可通过 cv.timezone() 获取)进行日期时间转换。

TextArea { value } —— 多行文本区域。

应用输入更改:

rust
let mut config = cv.script_config(id).unwrap_or_default();
// 对于索引 0 处值为 20 的 Int 输入:
config.input_values.insert(0, serde_json::json!(20));
// 对于 Source 输入,存储整数判别值:
config.input_values.insert(1, serde_json::json!(3)); // close
cv.set_script_config(id, config);

更改应立即应用(实时预览)—— 图表重新执行脚本并自动重绘。

策略配置标签页

对于策略脚本,可以提供专用标签页(或分区),让用户覆盖 strategy() 的执行参数,而无需修改源码。这些覆盖存储在 ScriptConfig::strategy_config_override 中。

rust
use navi_vm::StrategyConfigOverride;

let mut config = cv.script_config(id).unwrap_or_default();
config.strategy_config_override = Some(StrategyConfigOverride {
    initial_capital: Some(50_000.0),
    commission_value: Some(0.1),
    ..Default::default()
});
cv.set_script_config(id, config);

StrategyConfigOverride 字段(均为 Option<T>None = 使用脚本默认值):

字段说明默认值
initial_capital初始账户资金1_000_000
commission_type佣金计算方式:percentcash_per_contractcash_per_orderpercent
commission_value佣金金额。percent 模式下为百分比数值(1 = 1%);cash_per_contractcash_per_order 模式下为每合约或每笔订单的绝对金额。0
margin_long多头保证金比率(%)100
margin_short空头保证金比率(%)100
slippage每笔成交滑点,单位:tick0
pyramiding同方向最大开仓次数0
risk_free_rate年化无风险利率(%),用于计算夏普/索提诺比率2
process_orders_on_close在 bar 收盘价成交,而非下一根 bar 开盘价false
calc_on_order_fills订单成交后重新执行脚本false
backtest_fill_limits_assumption限价单成交所需超出限价的额外 tick 数0
close_entries_rule优先平仓规则:FIFOANYFIFO

strategy_config_override 的变更会触发完整的 session 重启(与输入值变更相同),因为回测结果依赖这些参数。

视觉标签页

视觉标签页布局视觉标签页布局

视觉标签页显示每个序列图的视觉覆盖。获取数据:

rust
let graph_configs: HashMap<SeriesGraphId, SeriesGraphConfig> = cv.graph_configs(id).unwrap();
let overrides: HashMap<SeriesGraphId, SeriesGraphOverride> = cv.script_overrides(id).unwrap();

SeriesGraphConfig 变体

SeriesGraphConfig 描述原始(覆盖前)的视觉状态。每个变体对应一种绘图类型:

rust
pub enum SeriesGraphConfig {
    Plot {
        title: Option<String>,
        colors: Vec<Option<Color>>,          // 不同的颜色槽位
        line_width: i32,
        style: PlotStyle,
        line_style: PlotLineStyle,
    },
    PlotChar {
        title: Option<String>,
        colors: Vec<Option<Color>>,
        char_value: char,
        location: Location,
        size: Size,
    },
    PlotShape {
        title: Option<String>,
        colors: Vec<Option<Color>>,
        style: Shape,
        location: Location,
        size: Size,
    },
    PlotArrow {
        title: Option<String>,
        up_colors: Vec<Option<Color>>,       // 上箭头颜色槽位
        down_colors: Vec<Option<Color>>,     // 下箭头颜色槽位
    },
    PlotCandle {
        title: Option<String>,
        colors: Vec<Option<Color>>,          // 柱体颜色槽位
        wick_colors: Vec<Option<Color>>,
        border_colors: Vec<Option<Color>>,
    },
    PlotBar {
        title: Option<String>,
        colors: Vec<Option<Color>>,
    },
    BackgroundColor {
        title: Option<String>,
        colors: Vec<Option<Color>>,
    },
    Fill {
        title: Option<String>,
        colors: Vec<Option<Color>>,
    },
}

颜色槽位colors 向量包含脚本使用的不同颜色(按首次出现顺序排列)。None 表示 na / 主题默认值。每个槽位在 SeriesGraphOverride::color_overrides 中有对应的位置。

SeriesGraphOverride

rust
pub struct SeriesGraphOverride {
    pub color_overrides: Vec<Option<Color>>,
    pub line_width: Option<i32>,
    pub style: Option<PlotStyle>,
    pub line_style: Option<PlotLineStyle>,
    pub char_value: Option<char>,
    pub shape: Option<Shape>,
    pub location: Option<Location>,
    pub size: Option<Size>,
    pub line_width_overrides: Vec<Option<i32>>,
    pub line_style_overrides: Vec<Option<PlotLineStyle>>,
    pub visible: bool,  // 默认为 true
}

UI 布局

视觉标签页渲染一个垂直的分区列表 —— 每个序列图一个分区,按 SeriesGraphId 排序。每个分区显示:

  1. 一个标题行,包含图形标题(来自 SeriesGraphConfig::title)或生成的名称如"Plot #1"。
  2. 色块 —— 每个不同的颜色槽位一个。
  3. 属性控件 —— 特定于类型(样式、宽度、形状等)。
  4. 可见性切换 —— 复选框或开关,控制 SeriesGraphOverride::visible

Plot(线/面积/直方图)

最复杂的类型 —— 每个颜色槽位有自己的线型和宽度:

控件字段
色块(每个槽位)color_overrides[i]颜色选择器。显示为使用有效颜色填充的矩形。None 槽位显示交叉阴影或"自动"指示器。
线宽(每个槽位)line_width_overrides[i]按钮组:1、2、3、4 像素。未设置时回退到全局 line_width
线型(每个槽位)line_style_overrides[i]按钮组或下拉框:SolidDashedDotted。未设置时回退到全局 line_style
绘图样式(全局)style下拉框,包含所有 PlotStyle 值 —— 见下表。
可见性visible复选框 / 切换开关。

PlotStyle 枚举值:

描述
Line连接各 K 线值的连续线
LineBrna 值处断开的线(不插值)
StepLine阶梯线
StepLineBrna 处断开的阶梯线
Area线下方的填充面积
AreaBrna 处断开的面积
Histogram从零线到值的垂直柱
Columns从零线到值的填充柱
Circles每根 K 线处的圆形标记
Cross每根 K 线处的十字标记
Diamond每根 K 线处的菱形标记

PlotLineStyle 枚举值:

虚线模式
Solid无虚线
Dashed[6, 3]
Dotted[2, 2]

每个槽位的覆盖布局line_width_overridesline_style_overrides 是与 color_overrides 相同索引的平行数组。如果数组长度小于颜色槽位数量,缺失的条目使用全局 line_width / line_style 覆盖值(或配置默认值)。

示例:一个有 3 种不同颜色的 plot 渲染 3 行,每行包含一个色块 + 线宽按钮 + 线型按钮:

[■ #2962FF] [1] [2] [3] [4]  [━━] [╌╌] [∙∙]
[■ #FF6D00] [1] [2] [3] [4]  [━━] [╌╌] [∙∙]
[■ #00BCD4] [1] [2] [3] [4]  [━━] [╌╌] [∙∙]
Style: [Line ▾]                    ☑ Visible

PlotChar(字符标记)

控件字段
色块(每个槽位)color_overrides[i]颜色选择器
字符char_value单字符文本输入。在每根 K 线上绘制的字符。
位置location下拉框 —— 见下方 Location 表
大小size下拉框 —— 见下方 Size 表
可见性visible复选框

PlotShape(形状标记)

控件字段
色块(每个槽位)color_overrides[i]颜色选择器
形状shape下拉框 —— 见下方 Shape 表
位置location下拉框 —— 见下方 Location 表
大小size下拉框 —— 见下方 Size 表
可见性visible复选框

PlotArrow(方向箭头)

PlotArrow 有两个独立的颜色组 —— 上箭头和下箭头:

控件字段说明
上颜色色块color_overrides[0..up_len]标签:"上颜色"。每个不同的上箭头颜色一个色块。
下颜色色块color_overrides[up_len..]标签:"下颜色"。偏移量为配置中的 up_colors.len()
可见性visible复选框

PlotCandle(OHLC K 线)

PlotCandle 有三个颜色组,使用扁平的 color_overrides 布局:

控件覆盖偏移量标签
柱体色块0..body_len"柱体"
影线色块body_len..body_len+wick_len"影线"
边框色块body_len+wick_len.."边框"
可见性visible复选框

其中 body_len = colors.len()wick_len = wick_colors.len() 来自配置。

PlotBar

控件字段
色块(每个槽位)color_overrides[i]
可见性visible

BackgroundColor(bgcolor)

控件字段
色块(每个槽位)color_overrides[i]
可见性visible

Fill

控件字段
色块(每个槽位)color_overrides[i]
可见性visible

共享枚举值

Location(用于 PlotChar / PlotShape):

描述
AboveBarK 线上方
BelowBarK 线下方
Top窗格顶部
Bottom窗格底部
AbsoluteY 位置来自序列浮点值

Size(用于 PlotChar / PlotShape):

描述
Auto自动大小
Tiny最小
Small
Normal默认
Large
Huge最大

Shape(用于 PlotShape):

描述
XCrossX 形
Cross+ 形
Circle实心圆
Diamond菱形
Square实心方形
TriangleUp向上三角形
TriangleDown向下三角形
ArrowUp向上箭头
ArrowDown向下箭头
Flag旗帜
LabelUp向上标签
LabelDown向下标签

颜色选择器

每个色块点击后应打开颜色选择器,包含:

  1. 预设调色板 —— 常用颜色网格(如 6x6)。
  2. 十六进制输入 —— 接受 #RRGGBB 格式的文本字段。
  3. 透明度滑块 —— 0-255 范围,控制 alpha 通道。

颜色编码:颜色是 RGBA 格式的打包 u32 值:(R << 24) | (G << 16) | (B << 8) | A

rust
// 从 Color 提取分量
let r = color.r(c);     // 0–255
let g = color.g(c);   // 0–255
let b = color.b(c);    // 0–255
let a = color.alpha();   // 0–255

// 从分量创建
let color = Color::from_rgba(255, 0, 0, 255); // 不透明红色

在 CSS 中显示:rgba({r}, {g}, {b}, {a / 255})

颜色覆盖编码

color_overrides 数组与 SeriesGraphConfig 中的颜色槽位对齐:

  • 单段类型(Plot、PlotChar、PlotShape、PlotBar、BackgroundColor、Fill):color_overrides[i] 对应 colors[i]
  • PlotArrowcolor_overrides = [..up_colors | ..down_colors](拼接)。前 up_colors.len() 个条目为上箭头覆盖,其余为下箭头。
  • PlotCandlecolor_overrides = [..colors | ..wick_colors | ..border_colors](拼接)。

None 条目表示"保留原始颜色"。Some(color) 条目替换原始值。

应用视觉更改

rust
let mut config = cv.script_config(id).unwrap_or_default();
let ovr = config.series_overrides.entry(graph_id).or_default();

// 将第一个颜色槽位覆盖为红色
ovr.color_overrides = vec![Some(Color::from_rgba(255, 0, 0, 255))];

// 将绘图样式改为直方图
ovr.style = Some(PlotStyle::Histogram);

// 隐藏此序列图
ovr.visible = false;

cv.set_script_config(id, config);

仅视觉更改会立即重新渲染,无需重新执行脚本。

有效值解析

在 UI 中显示属性的当前值时,使用三级回退解析:

  1. 覆盖值(来自 SeriesGraphOverride)—— 如已设置,使用该值。
  2. 配置默认值(来自 SeriesGraphConfig)—— 脚本的原始值。
  3. 主题默认值 —— 来自图表主题调色板的回退颜色。

恢复默认

将所有覆盖和输入重置为原始值:

rust
let mut config = ScriptConfig::default();
// 使用 InputInfo 中的原始默认值重新填充 input_values
for input in &inputs {
    config.input_values.insert(input.idx, input.default_value.clone());
}
// strategy_config_override 默认为 None,无需显式清除
cv.set_script_config(id, config);

这将清除所有 series_overridesstrategy_config_override 并重置输入,触发完全重新执行。

事件流概览

用户点击图例工具栏上的 ⚙

cv.on_mouse_up(x, y)  →  点击手势被检测到  →  ChartEvent::ConfigureScript(id) 推入队列

cv.poll_event()  →  宿主收到 ConfigureScript(id)

cv.tag_for(id)                   → 脚本标签(用于显示)
cv.script_inputs_effective(id)   → 携带当前值的 Vec<InputInfo>
cv.graph_configs(id)             → 每个图形的 SeriesGraphConfig
cv.script_overrides(id)          → 当前视觉覆盖

你的应用打开配置对话框

用户编辑输入或视觉属性

构建 ScriptConfig { series_overrides, input_values, strategy_config_override }
cv.set_script_config(id, config)

图表自动重新渲染(仅视觉)或重新执行(输入或策略配置变更)

如果输入已更改,重新获取 graph_configs(绘图结构可能已变更)

用户点击确定 → 关闭对话框
保存快照以便持久化

参考实现: 参见 Web Playground 中的 ScriptConfigDialog.vue,了解此 UI 模式的完整实现。

基于 MIT 许可证发布。