安全与执行限制
将 OpenPine 嵌入宿主应用程序时,用户提供的 Pine 脚本会在 VM 内执行。VM 提供可配置的限制,以保护宿主进程不受失控脚本的影响。
为何需要限制
Pine 脚本可以包含循环(for、while、for..in),其迭代次数可能根据用户输入或数据任意增加。若无限制,恶意或有缺陷的脚本可能导致宿主进程无限期挂起。OpenPine 的执行限制按 Bar 检查,因此开销可预测。
配置限制
在调用 build() 前,将 ExecutionLimits 传入 InstanceBuilder::with_execution_limits:
rust
use openpine_vm::{ExecutionLimits, Instance, TimeFrame};
let limits = ExecutionLimits::default()
.with_max_loop_iterations_per_bar(1_000_000);
let mut instance = Instance::builder(source, TimeFrame::days(1), "NASDAQ:AAPL")
.with_execution_limits(limits)
.build().await?;超出限制时,VM 会抛出运行时错误(Error::Exception),处理方式与其他运行时异常相同。
可用限制
max_loop_iterations_per_bar
| 属性 | 值 |
|---|---|
| 默认值 | 500,000 |
| 作用域 | 所有 for、while、for..in 循环在每个 Bar 内共享同一预算 |
| 重置时机 | 每根 K 线执行开始时计数器重置 |
| 禁用方式 | 设置为 u64::MAX 可关闭限制 |
同一 Bar 内所有循环类型共享同一预算。例如,脚本中两个嵌套 for 循环各迭代 1,000 次,则共消耗 1,000,000 次迭代——超过默认预算 500,000。
rust
// 为计算密集型脚本提高限制
let limits = ExecutionLimits::default()
.with_max_loop_iterations_per_bar(2_000_000);
// 完全禁用限制(不建议用于不受信任的脚本)
let limits = ExecutionLimits::default()
.with_max_loop_iterations_per_bar(u64::MAX);max_security_depth
| 属性 | 值 |
|---|---|
| 默认值 | 3 |
| 作用域 | request.security() 调用的最大嵌套深度 |
| 禁用方式 | 设置为 0 可完全禁止 request.security() |
控制 request.security() 的最大嵌套层数。深度为 1 表示 security 表达式内部不得再调用 request.security()。默认值 3 与 TradingView 行为一致。
rust
// 仅允许一层 request.security()(不允许嵌套)
let limits = ExecutionLimits::default()
.with_max_security_depth(1);
// 完全禁止 request.security()
let limits = ExecutionLimits::default()
.with_max_security_depth(0);max_security_calls
| 属性 | 值 |
|---|---|
| 默认值 | 40 |
| 作用域 | 所有 request.security() 调用点中,唯一 (symbol, timeframe) 组合的最大数量 |
| 禁用方式 | 设置为 0 可完全禁止 request.security() |
每个不同的 (symbol, timeframe) 组合会创建一个独立的数据流。共享同一组合的多个调用点只计一次。默认值 40 与 TradingView 行为一致。
rust
// 在资源受限的环境中收紧限制
let limits = ExecutionLimits::default()
.with_max_security_calls(10);处理超限错误
超限错误以 Error::Exception 的形式抛出,与 runtime.error() 及其他运行时错误类型相同:
rust
match instance.run_to_end("NASDAQ:AAPL", TimeFrame::days(1)).await {
Err(openpine_vm::Error::Exception(e)) => {
eprintln!("脚本错误:{}", e.display());
}
_ => {}
}有关处理运行时错误的完整说明,请参阅错误处理。
建议
- 不受信任的脚本:保持默认限制或将其调低。如无需使用
request.security(),可将max_security_depth设为1或0。 - 已知脚本:仅在确认脚本确实需要更多资源时才提高限制。
- 服务端执行:建议在独立线程中运行每个
Instance,并配合操作系统级别的超时作为二次保障。循环限制仅防止过多迭代,不能防范其他耗时计算来源。