脚本配置界面
当用户点击脚本图例上的 ⚙ 按钮时,图表会推送一个 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>:
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 非空,显示下拉框而非自由输入。遵循 min、max、step 约束。
Float { value, min, max, step, options } —— 带小数步长(默认 0.1)的数字输入框。options、min、max 行为与 Int 相同。
Bool { value } —— 切换开关。
Color { value } —— 色块 + 颜色选择器弹窗。颜色是 RGBA 格式的打包 u32:(R << 24) | (G << 16) | (B << 8) | A。显示为填充矩形;点击时打开包含十六进制输入和透明度滑块的颜色选择器。
Str { value, options } —— 文本输入框。如果 options 非空,显示下拉框。
Source { value } —— 固定选项的下拉框:open、high、low、close、hl2、hlc3、ohlc4、hlcc4。值为 SourceType 枚举。写入 input_values 时,转换为整数判别值:open=0、high=1、low=2、close=3、hl2=4、hlc3=5、ohlc4=6、hlcc4=7。
Enum { value, options } —— 下拉框。options 为 Vec<(i64, String)> ——(判别值,显示标签)对。在 input_values 中存储判别值。
Symbol { value } —— 交易标的代码的文本输入框(如 "AAPL")。
TimeFrame { value, options } —— 下拉框或文本输入。值为 TimeFrame。如果 options 非空,显示下拉框。
Session { value, options } —— 交易时段字符串的文本输入框或下拉框(如 "0930-1600")。
Time { value } —— 日期/时间选择器。值为自纪元以来的毫秒数(i64)。使用脚本的交易所时区(可通过 cv.timezone() 获取)进行日期时间转换。
TextArea { value } —— 多行文本区域。
应用输入更改:
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 中。
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 | 佣金计算方式:percent、cash_per_contract 或 cash_per_order | percent |
commission_value | 佣金金额。percent 模式下为百分比数值(1 = 1%);cash_per_contract 或 cash_per_order 模式下为每合约或每笔订单的绝对金额。 | 0 |
margin_long | 多头保证金比率(%) | 100 |
margin_short | 空头保证金比率(%) | 100 |
slippage | 每笔成交滑点,单位:tick | 0 |
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 | 优先平仓规则:FIFO 或 ANY | FIFO |
strategy_config_override 的变更会触发完整的 session 重启(与输入值变更相同),因为回测结果依赖这些参数。
视觉标签页
视觉标签页显示每个序列图的视觉覆盖。获取数据:
let graph_configs: HashMap<SeriesGraphId, SeriesGraphConfig> = cv.graph_configs(id).unwrap();
let overrides: HashMap<SeriesGraphId, SeriesGraphOverride> = cv.script_overrides(id).unwrap();SeriesGraphConfig 变体
SeriesGraphConfig 描述原始(覆盖前)的视觉状态。每个变体对应一种绘图类型:
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
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 排序。每个分区显示:
- 一个标题行,包含图形标题(来自
SeriesGraphConfig::title)或生成的名称如"Plot #1"。 - 色块 —— 每个不同的颜色槽位一个。
- 属性控件 —— 特定于类型(样式、宽度、形状等)。
- 可见性切换 —— 复选框或开关,控制
SeriesGraphOverride::visible。
Plot(线/面积/直方图)
最复杂的类型 —— 每个颜色槽位有自己的线型和宽度:
| 控件 | 字段 | 值 |
|---|---|---|
| 色块(每个槽位) | color_overrides[i] | 颜色选择器。显示为使用有效颜色填充的矩形。None 槽位显示交叉阴影或"自动"指示器。 |
| 线宽(每个槽位) | line_width_overrides[i] | 按钮组:1、2、3、4 像素。未设置时回退到全局 line_width。 |
| 线型(每个槽位) | line_style_overrides[i] | 按钮组或下拉框:Solid、Dashed、Dotted。未设置时回退到全局 line_style。 |
| 绘图样式(全局) | style | 下拉框,包含所有 PlotStyle 值 —— 见下表。 |
| 可见性 | visible | 复选框 / 切换开关。 |
PlotStyle 枚举值:
| 值 | 描述 |
|---|---|
Line | 连接各 K 线值的连续线 |
LineBr | 在 na 值处断开的线(不插值) |
StepLine | 阶梯线 |
StepLineBr | 在 na 处断开的阶梯线 |
Area | 线下方的填充面积 |
AreaBr | 在 na 处断开的面积 |
Histogram | 从零线到值的垂直柱 |
Columns | 从零线到值的填充柱 |
Circles | 每根 K 线处的圆形标记 |
Cross | 每根 K 线处的十字标记 |
Diamond | 每根 K 线处的菱形标记 |
PlotLineStyle 枚举值:
| 值 | 虚线模式 |
|---|---|
Solid | 无虚线 |
Dashed | [6, 3] |
Dotted | [2, 2] |
每个槽位的覆盖布局:line_width_overrides 和 line_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 ▾] ☑ VisiblePlotChar(字符标记)
| 控件 | 字段 | 值 |
|---|---|---|
| 色块(每个槽位) | 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):
| 值 | 描述 |
|---|---|
AboveBar | K 线上方 |
BelowBar | K 线下方 |
Top | 窗格顶部 |
Bottom | 窗格底部 |
Absolute | Y 位置来自序列浮点值 |
Size(用于 PlotChar / PlotShape):
| 值 | 描述 |
|---|---|
Auto | 自动大小 |
Tiny | 最小 |
Small | 小 |
Normal | 默认 |
Large | 大 |
Huge | 最大 |
Shape(用于 PlotShape):
| 值 | 描述 |
|---|---|
XCross | X 形 |
Cross | + 形 |
Circle | 实心圆 |
Diamond | 菱形 |
Square | 实心方形 |
TriangleUp | 向上三角形 |
TriangleDown | 向下三角形 |
ArrowUp | 向上箭头 |
ArrowDown | 向下箭头 |
Flag | 旗帜 |
LabelUp | 向上标签 |
LabelDown | 向下标签 |
颜色选择器
每个色块点击后应打开颜色选择器,包含:
- 预设调色板 —— 常用颜色网格(如 6x6)。
- 十六进制输入 —— 接受
#RRGGBB格式的文本字段。 - 透明度滑块 —— 0-255 范围,控制 alpha 通道。
颜色编码:颜色是 RGBA 格式的打包 u32 值:(R << 24) | (G << 16) | (B << 8) | A。
// 从 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]。 - PlotArrow:
color_overrides = [..up_colors | ..down_colors](拼接)。前up_colors.len()个条目为上箭头覆盖,其余为下箭头。 - PlotCandle:
color_overrides = [..colors | ..wick_colors | ..border_colors](拼接)。
None 条目表示"保留原始颜色"。Some(color) 条目替换原始值。
应用视觉更改
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 中显示属性的当前值时,使用三级回退解析:
- 覆盖值(来自
SeriesGraphOverride)—— 如已设置,使用该值。 - 配置默认值(来自
SeriesGraphConfig)—— 脚本的原始值。 - 主题默认值 —— 来自图表主题调色板的回退颜色。
恢复默认
将所有覆盖和输入重置为原始值:
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_overrides、strategy_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 模式的完整实现。