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 參考