Reading Outputs
After executing bars, you can inspect the visual outputs via instance.chart() and script metadata via instance.script_info().
For the complete chart data model — every field, enum, and rendering algorithm — see Chart Rendering.
Accessing Graphs
The chart contains series graphs (per-bar data) and graphs (point-in-time drawing objects):
rust
let chart = instance.chart();
// Series graphs: one value per bar
for (id, graph) in chart.series_graphs() {
match graph {
SeriesGraph::Plot(plot) => { /* line, area, histogram, etc. */ }
SeriesGraph::PlotCandle(candle) => { /* OHLC candle overlay */ }
SeriesGraph::PlotShape(shape) => { /* shape markers */ }
SeriesGraph::PlotArrow(arrow) => { /* arrow markers */ }
SeriesGraph::PlotBar(bar) => { /* OHLC bar chart */ }
SeriesGraph::PlotChar(ch) => { /* character markers */ }
SeriesGraph::BackgroundColors(bg) => { /* background colors */ }
SeriesGraph::Fill(fill) => { /* fill between plots */ }
}
}
// Point-in-time graphs
for (id, graph) in chart.graphs() {
match graph {
Graph::Label(label) => { /* text annotation */ }
Graph::Line(line) => { /* line segment */ }
Graph::Box(bx) => { /* rectangle */ }
Graph::Table(table) => { /* cell grid */ }
Graph::Hline(hline) => { /* horizontal line */ }
Graph::LineFill(fill) => { /* fill between two lines */ }
Graph::Polyline(poly) => { /* multi-point line */ }
}
}You can also look up individual graphs by ID:
rust
if let Some(sg) = chart.series_graph(id) {
// ...
}
if let Some(g) = chart.graph(id) {
// ...
}Script Info
Inspect the compiled script's metadata:
rust
let info = instance.script_info();
match &info.script_type {
ScriptType::Indicator(ind) => {
println!("Indicator: {}", ind.title);
println!("Overlay: {}", ind.overlay);
}
ScriptType::Strategy(strat) => {
println!("Strategy: {}", strat.title);
println!("Initial capital: {}", strat.initial_capital);
}
ScriptType::Library(lib) => {
println!("Library: {}", lib.title);
}
}
// List all inputs
for input in &info.inputs {
// Each input variant has: id, title, tooltip, default_value, etc.
}
// Alert conditions
for alert in &info.alert_conditions {
// Alert condition definitions
}Events
Events are produced during execution and yielded by the stream returned from instance.run(). Event types include:
| Event | Description |
|---|---|
BarStart(BarStartEvent) | Start of a bar's execution. Contains bar_index, timestamp, and bar_state. |
BarEnd | End of a bar's execution. |
HistoryEnd | Boundary between historical and real-time bars. |
Log(LogEvent) | A log message with level (Info, Warning, Error) and message. |
Alert(AlertEvent) | An alert with optional id and message. |
Draw(DrawEvent) | A drawing instruction (only in OutputMode::Stream). |
rust
use std::pin::pin;
use futures_util::StreamExt;
use openpine_vm::{Event, LogLevel};
let mut stream = pin!(instance.run(symbol, tf));
while let Some(result) = stream.next().await {
match result? {
Event::Log(log) => {
match log.level {
LogLevel::Info => println!("INFO: {}", log.message),
LogLevel::Warning => println!("WARN: {}", log.message),
LogLevel::Error => println!("ERROR: {}", log.message),
}
}
Event::Alert(alert) => {
println!("ALERT [id={:?}]: {}", alert.id, alert.message);
}
Event::HistoryEnd => {
println!("History replay complete");
}
_ => {}
}
}If you don't need to process events individually, use run_to_end():
rust
instance.run_to_end(symbol, tf).await?;
// Events are discarded; read results from instance.chart(), etc.Complete Example
rust
use std::pin::pin;
use futures_util::StreamExt;
use openpine_vm::{Candlestick, Event, Instance, TimeFrame};
async fn run(candles: Vec<Candlestick>) -> Result<(), openpine_vm::Error> {
let source = r#"
//@version=6
indicator("RSI Monitor")
rsi = ta.rsi(close, 14)
plot(rsi, "RSI")
hline(70, "Overbought")
hline(30, "Oversold")
alertcondition(ta.crossover(rsi, 70), "RSI Overbought")
"#;
let tf = TimeFrame::days(1);
let symbol = "NASDAQ:AAPL";
let mut instance = Instance::builder(candles, source, tf, symbol)
.build().await?;
// Consume the event stream
let mut stream = pin!(instance.run(symbol, tf));
while let Some(result) = stream.next().await {
if let Event::Alert(alert) = result? {
println!("Alert: {}", alert.message);
}
}
drop(stream);
// Print final RSI values
for (_id, graph) in instance.chart().series_graphs() {
if let Some(plot) = graph.as_plot() {
if plot.title.as_deref() == Some("RSI") {
if let Some(last) = plot.series.last() {
println!("Final RSI: {:?}", last);
}
}
}
}
Ok(())
}Next Steps
- Chart Rendering — complete chart data model and rendering guide
- Error Handling — handling compile and runtime errors
- C/C++ API — use from C++