C/C++ API
OpenPine 提供带有 C++ 包装器的 C ABI 绑定,允许你在 C 和 C++ 应用程序中嵌入 Pine Script 引擎。
要求
- C++17 编译器
- CMake 3.11+
- Rust 工具链(用于构建原生库)
使用 CMake 设置
C++ API 使用 Corrosion 从 CMake 构建 Rust 库:
cmake
cmake_minimum_required(VERSION 3.11)
project(my_project)
add_subdirectory(path/to/openpine)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE openpine_capi)基本用法
cpp
#include <openpine.hpp>
#include <iostream>
int main() {
const char* script = R"(
//@version=6
indicator("SMA")
plot(ta.sma(close, 5))
)";
// 创建实例
openpine::CreateInstanceOptions opts(script, "1D", "NASDAQ:AAPL");
try {
openpine::MyProvider provider(candlesticks);
opts.setDataProvider(&provider);
auto instance = openpine::Instance::create(opts);
// 异步执行,回调在执行线程上触发
std::promise<void> done;
instance.run("NASDAQ:AAPL", "1D", 0, [&done](const openpine::Result& r) {
if (!r.isSuccess())
std::cerr << "Error: " << r.errorMessage() << std::endl;
done.set_value();
});
done.get_future().wait();
// 读取图表输出
auto chart = instance.chart();
auto iter = chart.seriesGraphIterator(
openpine::SeriesGraphType::Plot
);
while (iter.next()) {
const auto plot = iter.seriesGraph().asPlot().value();
std::cout << "Plot: " << plot.title() << std::endl;
for (size_t i = 0; i < chart.seriesLength(); i++) {
auto val = plot.value(i);
if (val.has_value()) {
std::cout << " bar " << i << ": " << val.value()
<< std::endl;
}
}
}
} catch (const openpine::Error& e) {
std::cerr << "Error: " << e.errorMessage() << std::endl;
return 1;
}
return 0;
}核心 C++ 类型
| 类型 | 描述 |
|---|---|
CreateInstanceOptions | 配置:源码、时间周期、标的,可选 DataProvider 和 OutputMode |
Instance | 已编译的可执行脚本 |
DataProvider | 抽象基类:实现 symbolInfo + candlesticksOpen |
CandlestickStream | RAII 推送流;在 candlesticksOpen 里创建,可从任意线程推数据 |
CandlestickItem | K 线加 confirmed 标志(true = 已收盘,false = 正在形成) |
Chart | 视觉输出集合 |
SeriesGraphIterator | 迭代序列图(可选类型过滤) |
GraphIterator | 迭代时间点图形 |
SeriesGraph | 标记联合体(Plot、PlotCandle、PlotShape 等) |
Graph | 标记联合体(Label、Line、Box、Table 等) |
Error | 带错误信息和可选 span 的异常 |
输出模式
在 CreateInstanceOptions 上设置输出模式,控制 plot() 数据的产出方式:
cpp
openpine::CreateInstanceOptions opts(script, "1D", "NASDAQ:AAPL");
opts.setOutputMode(ffi::OutputMode::Stream);| 模式 | 行为 |
|---|---|
OutputMode::Chart(默认) | 绘图数据写入 instance.chart() |
OutputMode::Stream | 绘图数据通过事件回调发出 |
事件回调
向 Instance::run() 传入可选的事件回调,在脚本执行时逐个接收事件:
cpp
instance.run("NASDAQ:AAPL", "1D", 0,
// 完成回调
[&done](const openpine::Result& r) {
done.set_value();
},
// 事件回调(可选)
[](const ffi::Event& event) {
switch (event.kind) {
case ffi::EventKind::BarStart:
std::cout << "K线 " << event.bar_start.bar_index << std::endl;
break;
case ffi::EventKind::HistoryEnd:
std::cout << "历史回放完成" << std::endl;
break;
case ffi::EventKind::DrawUpdatePlot:
std::cout << "绘图 " << event.draw_update_plot.id
<< " = " << event.draw_update_plot.value << std::endl;
break;
default:
break;
}
}
);不传事件回调(或传 nullptr)时,run() 直接执行到完成,无逐事件通知。
喂入数据
实现 DataProvider 并在 candlesticksOpen 回调里创建 CandlestickStream 推数据:
cpp
class MyProvider : public openpine::DataProvider {
public:
explicit MyProvider(const std::vector<openpine::Candlestick>& bars)
: bars_(bars) {}
openpine::PartialSymbolInfo symbolInfo(std::string_view) override {
return {}; // 使用默认值
}
ffi::CandlestickStream* candlesticksOpen(
std::string_view symbol, std::string_view timeframe,
int64_t from_time) override {
auto stream = std::make_unique<openpine::CandlestickStream>(
symbol, timeframe, from_time);
for (const auto& bar : bars_)
stream->push(openpine::CandlestickItem{bar, true});
stream->finish();
return stream->release();
}
private:
std::vector<openpine::Candlestick> bars_;
};
// 使用
MyProvider provider(candlesticks);
opts.setDataProvider(&provider);
auto instance = openpine::Instance::create(opts);
std::promise<void> done;
instance.run("NASDAQ:AAPL", "1D", 0, [&done](const openpine::Result& r) {
done.set_value();
});
done.get_future().wait();如需异步推送(实时数据),在 candlesticksOpen 里启动独立线程推数据:
cpp
ffi::CandlestickStream* candlesticksOpen(...) override {
auto* stream = new openpine::CandlestickStream(symbol, timeframe, from_time);
std::thread([stream, this]() {
for (auto& bar : fetch_bars())
stream->push(openpine::CandlestickItem{bar, true});
stream->finish();
delete stream;
}).detach();
return stream->handle();
}访问图形
执行 K 线后,调用 instance.chart() 访问所有视觉输出。图表提供两种迭代器类型:
| 方法 | 过滤器 | 内容 |
|---|---|---|
chart.seriesGraphIterator(type?) | SeriesGraphType | 逐 K 线数据:绘图、背景、填充、K 线、形状、箭头 |
chart.graphIterator(type?) | GraphType | 时间点对象:标签、线条、框、表格、水平线、折线 |
两种迭代器都接受可选的类型过滤器。传入 std::nullopt 可迭代所有类型。
cpp
auto chart = instance.chart();
auto length = chart.seriesLength();
// 序列图:每根 K 线一个值
auto iter = chart.seriesGraphIterator(std::nullopt);
while (iter.next()) {
auto sg = iter.seriesGraph();
if (sg.type() == openpine::SeriesGraphType::Plot) {
auto plot = sg.asPlot().value();
// plot.value(i), plot.color(i), plot.title(), ...
}
if (sg.type() == openpine::SeriesGraphType::PlotCandle) {
auto candle = sg.asPlotCandle().value();
// candle.value(i) -> std::optional<Bar>
}
// PlotShape, PlotArrow, PlotBar, PlotChar, BackgroundColors, Fill
}
// 时间点图形
auto giter = chart.graphIterator(std::nullopt);
while (giter.next()) {
auto g = giter.graph();
if (g.type() == openpine::GraphType::Label) {
auto label = g.asLabel().value();
// label.x(), label.y(), label.text(), ...
}
if (g.type() == openpine::GraphType::Line) {
auto line = g.asLine().value();
// line.x1(), line.y1(), line.x2(), line.y2(), ...
}
// Box, Table, Hline, LineFill, Polyline
}有关完整的图表数据模型(所有字段、枚举和渲染算法),请参阅图表渲染。
错误处理
所有错误以 openpine::Error 异常抛出:
cpp
try {
opts.setDataProvider(&provider);
auto instance = openpine::Instance::create(opts);
std::promise<void> done;
instance.run("NASDAQ:AAPL", "1D", 0, [&](const openpine::Result& r) {
done.set_value();
});
done.get_future().wait();
} catch (const openpine::Error& e) {
std::cerr << "Error: " << e.errorMessage() << std::endl;
// 可选:获取错误源码位置
auto span = e.errorSpan();
if (span.has_value()) {
std::cerr << " at line " << span.value().startLine << std::endl;
}
}下一步
- LSP 与编辑器支持 — 语言服务器功能
- 集成 — Rust API 参考