OpenPine C++ API
C++ wrapper for the OpenPine Pine Script VM
Loading...
Searching...
No Matches
instance.hpp
Go to the documentation of this file.
1#pragma once
2
10
11#if (defined(_MSVC_LANG) ? _MSVC_LANG : __cplusplus) < 201703L
12#error \
13 "OpenPine C++ wrapper headers require C++17 (std::optional, std::string_view)."
14#endif
15
16#include <cstdint>
17#include <functional>
18#include <memory>
19#include <optional>
20#include <string>
21
22#include "chart.hpp"
23#include "error.hpp"
24#include "ffi.hpp"
25#include "script_info.hpp"
26#include "types.hpp"
27
28namespace openpine {
29
30// ---------------------------------------------------------------------------
31// CandlestickStream
32// ---------------------------------------------------------------------------
33
58 public:
64 CandlestickStream(std::string_view symbol, std::string_view timeframe,
65 int64_t from_time)
66 : ptr_(ffi::candlestickStreamCreate(
67 reinterpret_cast<const uint8_t*>(symbol.data()), symbol.size(),
68 reinterpret_cast<const uint8_t*>(timeframe.data()),
69 timeframe.size(), from_time)) {}
70
72 if (ptr_) finish();
73 }
74
77
79 void push(const CandlestickItem& item) {
80 std::unique_ptr<ffi::Result, decltype(&ffi::resultDelete)> result{
81 ffi::candlestickStreamPush(ptr_, &item), ffi::resultDelete};
82 if (!ffi::resultIsSuccess(&*result))
83 throw Error{ffi::resultErrorMessage(&*result),
84 ffi::resultErrorSpan(&*result)};
85 }
86
88 void finish() {
89 if (!ptr_) return;
90 std::unique_ptr<ffi::Result, decltype(&ffi::resultDelete)> result{
91 ffi::candlestickStreamFinish(ptr_), ffi::resultDelete};
92 // Ignore errors from finish — the stream pointer is no longer usable.
93 (void)result;
94 ptr_ = nullptr;
95 }
96
105 ffi::CandlestickStream* release() {
106 auto* p = ptr_;
107 ptr_ = nullptr;
108 return p;
109 }
110
112 ffi::CandlestickStream* handle() const { return ptr_; }
113
114 private:
115 ffi::CandlestickStream* ptr_;
116};
117
118// ---------------------------------------------------------------------------
119// DataProvider
120// ---------------------------------------------------------------------------
121
154class DataProvider {
155 public:
156 virtual ~DataProvider() = default;
157
162 virtual PartialSymbolInfo symbolInfo(std::string_view symbol) = 0;
163
172 virtual ffi::CandlestickStream* candlesticksOpen(std::string_view symbol,
173 std::string_view timeframe,
174 int64_t from_time) = 0;
175};
176
177// ---------------------------------------------------------------------------
178// CreateInstanceOptions
179// ---------------------------------------------------------------------------
180
185 public:
186 CreateInstanceOptions(const std::string& source, const std::string& timeframe,
187 const std::string& symbol,
188 const std::optional<std::string>& path = std::nullopt)
189 : source_(source),
190 timeframe_(timeframe),
191 path_(path),
192 symbol_(symbol),
193 background_color_(0xff),
194 last_info_(std::nullopt) {}
195
197 void setBackgroundColor(uint32_t color) { background_color_ = color; }
198
200 void setLastInfo(const LastInfo& last_info) { last_info_ = last_info; }
201
206 void setDataProvider(DataProvider* provider) { data_provider_ = provider; }
207
213 void setOutputMode(ffi::COutputMode mode) { output_mode_ = mode; }
214
215 friend class Instance;
216
217 private:
218 std::string source_;
219 std::optional<std::string> path_;
220 std::string timeframe_;
221 std::string symbol_;
222 uint32_t background_color_;
223 std::optional<LastInfo> last_info_;
224 DataProvider* data_provider_ = nullptr;
225 ffi::COutputMode output_mode_ = ffi::COutputMode::Chart;
226};
227
228// ---------------------------------------------------------------------------
229// Instance
230// ---------------------------------------------------------------------------
231
235class Instance {
236 public:
244 using RunCallback = std::function<void(const Result&)>;
245
251 using EventCallback = std::function<void(const ffi::CEvent&)>;
252
257 static Instance create(const CreateInstanceOptions& options);
258
260 Chart chart() const { return Chart{ffi::instanceChart(&*p_)}; }
261
264 return ScriptInfo{ffi::instanceScriptInfo(&*p_)};
265 }
266
283 void run(std::string_view symbol, std::string_view timeframe,
284 int64_t from_time, RunCallback callback,
285 EventCallback event_callback = nullptr);
286
287 Instance(Instance&&) = default;
289
290 private:
291 explicit Instance(ffi::Instance* p) : p_(p, ffi::instanceDelete) {}
292
293 std::unique_ptr<ffi::Instance, decltype(&ffi::instanceDelete)> p_{
294 nullptr, ffi::instanceDelete};
295
296 // Heap-allocated trampoline that bridges C++ DataProvider virtuals to the
297 // ffi::DataProvider function-pointer table.
298 struct ProviderTrampoline {
299 DataProvider* provider;
300
301 static const char* symbol_info_fn(void* ctx, const uint8_t* sym,
302 size_t sym_len,
303 ffi::PartialSymbolInfo* out) {
304 auto* t = static_cast<ProviderTrampoline*>(ctx);
305 std::string_view sv(reinterpret_cast<const char*>(sym), sym_len);
306 try {
307 *out = t->provider->symbolInfo(sv);
308 return nullptr;
309 } catch (const std::exception& e) {
310 static thread_local std::string buf;
311 buf = e.what();
312 return buf.c_str();
313 }
314 }
315
316 static ffi::CandlestickStream* candlesticks_open_fn(
317 void* ctx, const uint8_t* sym, size_t sym_len, const uint8_t* tf,
318 size_t tf_len, int64_t from_time) {
319 auto* t = static_cast<ProviderTrampoline*>(ctx);
320 std::string_view sv(reinterpret_cast<const char*>(sym), sym_len);
321 std::string_view tfv(reinterpret_cast<const char*>(tf), tf_len);
322 try {
323 return t->provider->candlesticksOpen(sv, tfv, from_time);
324 } catch (...) {
325 return nullptr;
326 }
327 }
328 };
329
330 std::unique_ptr<ProviderTrampoline> trampoline_;
331 std::optional<ffi::DataProvider> ffi_provider_;
332};
333
334// ---------------------------------------------------------------------------
335// Instance::create (inline definition)
336// ---------------------------------------------------------------------------
337
339 const ffi::PineStringRef* path_ptr = nullptr;
340 ffi::PineStringRef ffi_path;
341 if (options.path_) {
342 ffi_path = {reinterpret_cast<const uint8_t*>(options.path_->data()),
343 options.path_->size()};
344 path_ptr = &ffi_path;
345 }
346 ffi::PineStringRef source{
347 reinterpret_cast<const uint8_t*>(options.source_.data()),
348 options.source_.size()};
349 ffi::PineStringRef timeframe{
350 reinterpret_cast<const uint8_t*>(options.timeframe_.data()),
351 options.timeframe_.size()};
352 ffi::PineStringRef symbol{
353 reinterpret_cast<const uint8_t*>(options.symbol_.data()),
354 options.symbol_.size()};
355
356 Instance inst(nullptr);
357
358 const ffi::DataProvider* provider_ptr = nullptr;
359 if (options.data_provider_) {
360 inst.trampoline_ = std::make_unique<ProviderTrampoline>();
361 inst.trampoline_->provider = options.data_provider_;
362 inst.ffi_provider_ = ffi::DataProvider{
363 static_cast<void*>(inst.trampoline_.get()),
364 ProviderTrampoline::symbol_info_fn,
365 ProviderTrampoline::candlesticks_open_fn,
366 };
367 provider_ptr = &*inst.ffi_provider_;
368 }
369
370 ffi::CreateInstanceOptions ffi_opts{source,
371 path_ptr,
372 timeframe,
373 symbol,
374 &options.background_color_,
375 options.last_info_
376 ? &*options.last_info_
377 : nullptr,
378 provider_ptr,
379 options.output_mode_};
380
381 ffi::Instance* raw = nullptr;
382 std::unique_ptr<ffi::Result, decltype(&ffi::resultDelete)> result{
383 ffi::instanceCreate(&ffi_opts, &raw), ffi::resultDelete};
384 if (!ffi::resultIsSuccess(&*result))
385 throw Error{ffi::resultErrorMessage(&*result),
386 ffi::resultErrorSpan(&*result)};
387
388 inst.p_.reset(raw);
389 return inst;
390}
391
392// ---------------------------------------------------------------------------
393// Instance::run (inline definition)
394// ---------------------------------------------------------------------------
395
396inline void Instance::run(std::string_view symbol, std::string_view timeframe,
397 int64_t from_time, RunCallback callback,
398 EventCallback event_callback) {
399 // Pack both callbacks into a single heap-allocated struct so they can be
400 // passed through the C ABI as a single void* user_data pointer.
401 struct Callbacks {
403 EventCallback event;
404 };
405 auto* cbs = new Callbacks{std::move(callback), std::move(event_callback)};
406
407 auto c_callback = [](const ffi::Result* result, void* ud) noexcept {
408 auto* cbs = static_cast<Callbacks*>(ud);
409 try {
410 cbs->run(Result{result});
411 } catch (...) {
412 }
413 delete cbs;
414 };
415
416 // C-level event trampoline — only set when EventCallback is non-null.
417 ffi::InstanceEventCallback c_event_callback = nullptr;
418 if (cbs->event) {
419 c_event_callback = [](const ffi::CEvent* event, void* ud) noexcept {
420 auto* cbs = static_cast<Callbacks*>(ud);
421 try {
422 cbs->event(*event);
423 } catch (...) {
424 }
425 };
426 }
427
428 std::unique_ptr<ffi::Result, decltype(&ffi::resultDelete)> start_result{
429 ffi::instanceRun(
430 &*p_,
431 reinterpret_cast<const uint8_t*>(symbol.data()), symbol.size(),
432 reinterpret_cast<const uint8_t*>(timeframe.data()), timeframe.size(),
433 from_time, c_event_callback, c_callback, cbs),
434 ffi::resultDelete};
435
436 if (!ffi::resultIsSuccess(&*start_result)) {
437 delete cbs;
438 throw Error{ffi::resultErrorMessage(&*start_result),
439 ffi::resultErrorSpan(&*start_result)};
440 }
441}
442
443} // namespace openpine
C++ wrappers for chart/visual output produced by the VM.
CandlestickStream(const CandlestickStream &)=delete
void finish()
Signals end-of-stream (thread-safe). Idempotent.
Definition instance.hpp:88
CandlestickStream & operator=(const CandlestickStream &)=delete
void push(const CandlestickItem &item)
Pushes one bar into the stream (thread-safe).
Definition instance.hpp:79
ffi::CandlestickStream * release()
Returns the underlying raw handle and releases ownership.
Definition instance.hpp:105
ffi::CandlestickStream * handle() const
Returns the raw handle without releasing ownership.
Definition instance.hpp:112
CandlestickStream(std::string_view symbol, std::string_view timeframe, int64_t from_time)
Creates a new stream.
Definition instance.hpp:64
Chart data produced by the VM.
Definition chart.hpp:35
Options for creating an Instance.
Definition instance.hpp:184
void setBackgroundColor(uint32_t color)
Sets the background color (0xAARRGGBB).
Definition instance.hpp:197
void setDataProvider(DataProvider *provider)
Injects a DataProvider.
Definition instance.hpp:206
void setLastInfo(const LastInfo &last_info)
Sets last-bar info.
Definition instance.hpp:200
CreateInstanceOptions(const std::string &source, const std::string &timeframe, const std::string &symbol, const std::optional< std::string > &path=std::nullopt)
Definition instance.hpp:186
void setOutputMode(ffi::COutputMode mode)
Sets the output mode.
Definition instance.hpp:213
virtual ffi::CandlestickStream * candlesticksOpen(std::string_view symbol, std::string_view timeframe, int64_t from_time)=0
Opens a candlestick stream.
virtual PartialSymbolInfo symbolInfo(std::string_view symbol)=0
Returns symbol metadata. Throw on failure.
virtual ~DataProvider()=default
Represents an error that occurred during script compilation or execution.
Definition error.hpp:25
static Instance create(const CreateInstanceOptions &options)
Creates a new Instance.
Definition instance.hpp:338
Chart chart() const
Returns the chart produced by the last completed run().
Definition instance.hpp:260
std::function< void(const ffi::CEvent &)> EventCallback
Callback invoked for each event during run().
Definition instance.hpp:251
void run(std::string_view symbol, std::string_view timeframe, int64_t from_time, RunCallback callback, EventCallback event_callback=nullptr)
Starts asynchronous execution and returns immediately.
Definition instance.hpp:396
Instance & operator=(Instance &&)=default
ScriptInfo scriptInfo() const
Returns the script metadata.
Definition instance.hpp:263
Instance(Instance &&)=default
std::function< void(const Result &)> RunCallback
Callback invoked when run() completes.
Definition instance.hpp:244
Script metadata (type, overlay, title, inputs, alerts) produced by the VM.
Error type used by the C++ wrapper API.
C++ wrapper for script metadata (ScriptInfo) from the OpenPine VM.
Re-exports FFI types into the openpine namespace.