PineForge unreleased
Deterministic PineScript v6 backtest runtime — C ABI reference
Loading...
Searching...
No Matches
hello_kernel_c.c
Go to the documentation of this file.
1/* hello, kernel — from C.
2 *
3 * The same host as hello_kernel.cpp, written against the C API instead of
4 * subclassing NativeStrategyHost: hand the runtime a callback table, describe
5 * the run once, feed it bars, read the closed trades back. No PineScript, no
6 * codegen, no dlopen, and no C++ in this file.
7 *
8 * cc -std=c11 hello_kernel_c.c -lpineforge -lstdc++ -o hello_kernel_c
9 */
10
11#include <pineforge/pineforge.h>
12
13#include <stdio.h>
14#include <string.h>
15
16/* open, high, low, close, volume, timestamp (Unix milliseconds). */
17static const pf_bar_t kBars[] = {
18 {100.0, 102.0, 99.0, 101.0, 4.0, 0},
19 {102.0, 103.0, 101.0, 102.0, 4.0, 300000},
20 {103.0, 104.0, 102.0, 103.5, 4.0, 600000},
21 {103.5, 105.0, 103.0, 104.0, 4.0, 900000}
22};
23enum { kBarCount = 4 };
24
25struct host_state {
26 pf_strategy_t handle;
27 int bars;
28};
29
30/* One calculation point per closed script bar. Requests submitted here are
31 * matched from the next eligible point on, never on the bar just closed. */
32static int on_bar(void* user, const pf_bar_t* bar, const pf_native_decision_v1* at) {
33 struct host_state* state = (struct host_state*)user;
35 (void)bar;
36 (void)at;
37
38 ++state->bars;
39 if (state->bars != 1 && state->bars != 3) return 0;
40
41 memset(&request, 0, sizeof(request));
42 request.struct_size = (uint32_t)sizeof(request);
43 request.version = PF_NATIVE_API_VERSION;
44 if (state->bars == 1) {
45 request.intent = PF_NATIVE_INTENT_TRANSACT;
46 request.intent_value = 1.0;
47 request.label = "hello-long";
48 } else {
49 request.intent = PF_NATIVE_INTENT_FLATTEN;
50 request.label = "hello-flat";
51 }
52 /* Returning non-zero here would end the run Failed with
53 * PF_NATIVE_FAILURE_CALLBACK, so report the refusal and keep going. */
54 if (strategy_native_submit_v1(state->handle, &request, NULL, NULL) != PF_NATIVE_OK) {
55 fprintf(stderr, "submit refused at bar %d\n", state->bars);
56 }
57 return 0;
58}
59
60/* Nothing is inferred: the spec names the clock, the instrument and the
61 * account. Validation refuses an incomplete value at configure time. */
64 memset(&spec, 0, sizeof(spec));
65 spec.struct_size = (uint32_t)sizeof(spec);
66 spec.session_key = "hello-kernel-c";
67 spec.run_number = 1;
68 spec.input_tf = "5";
69 spec.script_tf = "5";
70 spec.ticker = "MOCK";
71 spec.tickerid = "TEST:MOCK";
72 spec.type = "crypto";
73 spec.currency = "USDT";
74 spec.basecurrency = "ETH";
75 spec.description = "";
76 spec.volumetype = "";
77 spec.timezone = "UTC";
78 spec.session = "24x7";
79 spec.chart_timezone = "";
80 spec.initial_capital = 10000.0;
81 spec.point_value = 1.0;
82 spec.account_fx = 1.0;
83 spec.price_tick = 0.01;
85 spec.fee_value = 0.0;
88 return spec;
89}
90
91int main(void) {
92 struct host_state state;
93 pf_native_callbacks_v1 callbacks;
95 pf_report_t report;
96 int i;
97
98 memset(&state, 0, sizeof(state));
99 memset(&report, 0, sizeof(report));
100
101 memset(&callbacks, 0, sizeof(callbacks));
102 callbacks.struct_size = (uint32_t)sizeof(callbacks);
103 callbacks.version = PF_NATIVE_API_VERSION;
104 callbacks.user = &state;
105 callbacks.on_bar = on_bar;
106
107 state.handle = strategy_native_host_create_v1(&callbacks);
108 if (!state.handle) {
109 fprintf(stderr, "create: the runtime refused the callback table\n");
110 return 1;
111 }
112
113 if (strategy_configure_native_v1(state.handle, &spec) != 0) {
114 fprintf(stderr, "configure: %s\n", strategy_get_last_error(state.handle));
115 strategy_native_host_free(state.handle);
116 return 1;
117 }
118
119 if (strategy_native_run_v1(state.handle, kBars, kBarCount, &report) != PF_NATIVE_OK) {
120 fprintf(stderr, "run: %s\n", strategy_get_last_error(state.handle));
122 strategy_native_host_free(state.handle);
123 return 1;
124 }
125
126 printf("closed trades: %d\n", report.total_trades);
127 for (i = 0; i < report.total_trades; ++i) {
128 const pf_trade_t* trade = &report.trades[i];
129 printf(" %s qty=%g entry=%g exit=%g pnl=%g\n",
130 trade->is_long ? "long " : "short", trade->qty,
131 trade->entry_price, trade->exit_price, trade->pnl);
132 }
133
134 {
135 const int trades = report.total_trades;
137 strategy_native_host_free(state.handle);
138 return trades > 0 ? 0 : 1;
139 }
140}
const char * strategy_get_last_error(pf_strategy_t s)
Returns the error message captured by the most recent run_backtest / run_backtest_full call on this s...
int strategy_configure_native_v1(pf_strategy_t s, const pf_native_run_spec_v1 *spec)
Apply a native v1 specification.
int strategy_native_run_v1(pf_strategy_t s, const pf_bar_t *bars, int n, pf_report_t *out)
Run n bars as one batch and fill out.
void strategy_native_host_free(pf_strategy_t s)
Release a handle from strategy_native_host_create_v1.
pf_strategy_t strategy_native_host_create_v1(const pf_native_callbacks_v1 *callbacks)
Allocate a native host that forwards every kernel callback to callbacks.
int strategy_native_submit_v1(pf_strategy_t s, const pf_native_request_v1 *request, uint64_t *incarnation, uint32_t *reject)
Submit request.
void strategy_native_report_free_v1(pf_report_t *report)
Free the heap arrays inside a report filled by strategy_native_run_v1.
@ PF_NATIVE_INTENT_TRANSACT
intent_value signed units.
@ PF_NATIVE_INTENT_FLATTEN
Close the whole book.
@ PF_NATIVE_CLOSE_EXECUTION_NEXT_ELIGIBLE_POINT
A later eligible point — the next modeled opening, an observed print or a carried open — never the ba...
@ PF_NATIVE_OPEN_DIRECTIONS_BOTH
The kernel's default.
@ PF_NATIVE_FEE_PERCENT
fee_value percent of |units| × price × point value × account FX (the default).
#define PF_NATIVE_OK
Success.
static const pf_bar_t kBars[]
static pf_native_run_spec_v1 make_spec(void)
static int on_bar(void *user, const pf_bar_t *bar, const pf_native_decision_v1 *at)
int main(void)
@ kBarCount
#define PF_NATIVE_API_VERSION
Monotonic version of this header's native-C layouts.
void * pf_strategy_t
Opaque handle to a compiled strategy instance.
Definition pineforge.h:441
Single OHLCV bar pushed into the engine.
Definition pineforge.h:140
The C host's strategy logic.
Where the kernel is, presented to every callback.
One order request.
Versioned native run specification.
Definition pineforge.h:500
const char * tickerid
Definition pineforge.h:504
uint32_t allowed_open_directions
Definition pineforge.h:508
const char * volumetype
Definition pineforge.h:504
const char * basecurrency
Definition pineforge.h:504
const char * input_tf
Definition pineforge.h:503
const char * session_key
Definition pineforge.h:502
const char * type
Definition pineforge.h:504
const char * script_tf
Definition pineforge.h:503
const char * chart_timezone
Definition pineforge.h:505
const char * timezone
Definition pineforge.h:505
const char * ticker
Definition pineforge.h:504
const char * session
Definition pineforge.h:505
const char * description
Definition pineforge.h:504
const char * currency
Definition pineforge.h:504
Backtest report filled by run_backtest / run_backtest_full.
Definition pineforge.h:366
int total_trades
Logical closed-trade count, including the range-end close of a position still open after the final ba...
Definition pineforge.h:368
pf_trade_t * trades
Heap array of closed trades; script-driven exits first, then the range-end rows (open_at_end=1).
Definition pineforge.h:374
Closed-trade record returned in pf_report_t::trades.
Definition pineforge.h:166
double exit_price
Exit fill price (incl.
Definition pineforge.h:170
double pnl
Net realized PnL in account currency (commission-inclusive).
Definition pineforge.h:171
int is_long
1 if long, 0 if short.
Definition pineforge.h:180
double qty
Filled quantity.
Definition pineforge.h:183
double entry_price
Entry fill price (incl.
Definition pineforge.h:169