# of_ffi_c
`of_ffi_c` exposes a stable C ABI for embedding the Orderflow runtime in non-Rust environments.
It is the native interface used by Python (`ctypes`), Java (JNA), and any C-compatible host runtime.
## ABI Surface
- Engine lifecycle: `of_engine_create`, `of_engine_start`, `of_engine_stop`, `of_engine_destroy`
- Subscription: `of_subscribe`, `of_unsubscribe`, `of_unsubscribe_symbol`, `of_reset_symbol_session`
- External ingest and supervision: `of_ingest_trade`, `of_ingest_book`, `of_configure_external_feed`, `of_external_set_reconnecting`, `of_external_health_tick`
- Polling and snapshots: `of_engine_poll_once`, `of_get_book_snapshot`, `of_get_analytics_snapshot`, `of_get_derived_analytics_snapshot`, `of_get_session_candle_snapshot`, `of_get_interval_candle_snapshot`, `of_get_signal_snapshot`
- Metrics and memory management: `of_get_metrics_json`, `of_string_free`
## New In 0.3.0
The C ABI remains stable in `0.3.0`. Existing exported symbols are unchanged,
while `of_get_metrics_json(...)` returns additive runtime fields for
backpressure, aggregate adapter health, and circuit-breaker state.
## New In 0.2.0
Relative to the `0.1.x` line, the C ABI now exposes:
- `of_get_book_snapshot(...)`
- `of_get_derived_analytics_snapshot(...)`
- `of_get_session_candle_snapshot(...)`
- `of_get_interval_candle_snapshot(...)`
- `BOOK_SNAPSHOT` callback stream support
- `DERIVED_ANALYTICS` callback stream support
These are additive ABI extensions; existing lifecycle and polling calls remain
valid.
## Public ABI Inventory
Public C structs/types:
- `of_engine_config_t`
- `of_symbol_t`
- `of_trade_t`
- `of_book_t`
- `of_external_feed_policy_t`
- `of_error_t`
- `of_engine`
- `of_subscription`
- `of_event_t`
- `of_event_cb`
Exported C functions:
- `of_api_version`
- `of_build_info`
- `of_engine_create`
- `of_engine_start`
- `of_engine_stop`
- `of_engine_destroy`
- `of_subscribe`
- `of_unsubscribe`
- `of_unsubscribe_symbol`
- `of_reset_symbol_session`
- `of_ingest_trade`
- `of_ingest_book`
- `of_configure_external_feed`
- `of_external_set_reconnecting`
- `of_external_health_tick`
- `of_get_book_snapshot`
- `of_get_analytics_snapshot`
- `of_get_derived_analytics_snapshot`
- `of_get_session_candle_snapshot`
- `of_get_interval_candle_snapshot`
- `of_get_signal_snapshot`
- `of_get_metrics_json`
- `of_string_free`
- `of_engine_poll_once`
`of_get_book_snapshot` returns a materialized JSON snapshot with:
- `venue`
- `symbol`
- `bids`
- `asks`
- `last_sequence`
- `ts_exchange_ns`
- `ts_recv_ns`
`of_get_derived_analytics_snapshot` returns additive session metrics with:
- `total_volume`
- `trade_count`
- `vwap`
- `average_trade_size`
- `imbalance_bps`
`of_get_session_candle_snapshot` returns candle-style session state with:
- `open`
- `high`
- `low`
- `close`
- `trade_count`
- `first_ts_exchange_ns`
- `last_ts_exchange_ns`
`of_get_interval_candle_snapshot` returns rolling-window candle state for a caller-supplied `window_ns` with:
- `window_ns`
- `open`
- `high`
- `low`
- `close`
- `trade_count`
- `total_volume`
- `vwap`
- `first_ts_exchange_ns`
- `last_ts_exchange_ns`
Subscription stream ids:
- `1`: `BOOK` raw book updates
- `2`: `TRADES` raw trade prints
- `3`: `ANALYTICS` snapshot callbacks
- `4`: `SIGNALS` snapshot callbacks
- `5`: `HEALTH` transition callbacks
- `6`: `BOOK_SNAPSHOT` materialized book snapshot callbacks after book changes
- `7`: `DERIVED_ANALYTICS` session-derived analytics callbacks after trade changes
## C Struct Reference
`of_engine_config_t`:
- `instance_id`: optional runtime instance id override
- `config_path`: optional `.toml` or `.json` runtime config path
- `log_level`: reserved for host integrations
- `enable_persistence`: non-zero enables persistence
- `audit_max_bytes`: audit rotation size
- `audit_max_files`: audit retention count
- `audit_redact_tokens_csv`: comma-separated audit redaction tokens
- `data_retention_max_bytes`: persistence byte cap
- `data_retention_max_age_secs`: persistence age cap in seconds
`of_symbol_t`:
- `venue`: venue/exchange name
- `symbol`: normalized symbol string
- `depth_levels`: requested book depth for subscribe calls
`of_trade_t`:
- `symbol`: embedded [`of_symbol_t`]
- `price`, `size`: integer-normalized trade values
- `aggressor_side`: one of `OF_SIDE_BID` or `OF_SIDE_ASK`
- `sequence`: venue sequence or `0` when unavailable
- `ts_exchange_ns`, `ts_recv_ns`: exchange and local timestamps
`of_book_t`:
- `symbol`: embedded [`of_symbol_t`]
- `side`: one of `OF_SIDE_BID` or `OF_SIDE_ASK`
- `level`: top-of-book-relative depth index
- `price`, `size`: integer-normalized book values
- `action`: one of `OF_BOOK_ACTION_UPSERT` or `OF_BOOK_ACTION_DELETE`
- `sequence`: venue sequence or `0` when unavailable
- `ts_exchange_ns`, `ts_recv_ns`: exchange and local timestamps
`of_external_feed_policy_t`:
- `stale_after_ms`: max allowed ingest silence before stale status
- `enforce_sequence`: non-zero enables sequence-gap/out-of-order checks
`of_event_t` callback envelope:
- `kind`: stream kind id
- `payload` / `payload_len`: UTF-8 JSON payload bytes
- `schema_id`: payload schema id, currently `1`
- `quality_flags`: `OF_DQ_*` bits associated with the event
- timestamps are copied from the underlying event when available
## Function Family Reference
Lifecycle:
- `of_engine_create`
- `of_engine_start`
- `of_engine_stop`
- `of_engine_destroy`
Subscription:
- `of_subscribe`
- `of_unsubscribe`
- `of_unsubscribe_symbol`
- `of_reset_symbol_session`
External ingest and supervision:
- `of_ingest_trade`
- `of_ingest_book`
- `of_configure_external_feed`
- `of_external_set_reconnecting`
- `of_external_health_tick`
Polling and snapshots:
- `of_engine_poll_once`
- `of_get_book_snapshot`
- `of_get_analytics_snapshot`
- `of_get_derived_analytics_snapshot`
- `of_get_session_candle_snapshot`
- `of_get_interval_candle_snapshot`
- `of_get_signal_snapshot`
When the runtime backpressure limit is enabled through
`OF_RUNTIME_MAX_EVENTS_PER_POLL`, `of_engine_poll_once` returns
`OF_ERR_BACKPRESSURE` if a poll drains more events than the configured limit.
Metadata and ownership helpers:
- `of_api_version`
- `of_build_info`
- `of_get_metrics_json`
- `of_string_free`
## Safety Contract
Callers must:
- pass valid non-null pointers for required pointer arguments
- pass UTF-8 `char*` values where strings are expected
- preserve pointer validity for the full duration of each call
- free owned strings returned by the API using `of_string_free`
Additional ownership rules:
- snapshot getters that write into caller buffers do not allocate for the caller
- functions returning owned `char*` require `of_string_free`
- callback payload pointers are only valid for the duration of the callback
- opaque `of_engine_t*` and `of_subscription_t*` handles must be destroyed/unsubscribed only through exported API calls
## Minimal C Example
```c
#include "orderflow.h"
int main(void) {
of_engine_t* engine = NULL;
of_engine_config_t cfg = {0};
cfg.instance_id = "demo";
int32_t rc = of_engine_create(&cfg, &engine);
if (rc != OF_OK) return 1;
rc = of_engine_start(engine);
if (rc != OF_OK) {
of_engine_destroy(engine);
return 2;
}
of_engine_stop(engine);
of_engine_destroy(engine);
return 0;
}
```
## Error Semantics
Most functions return `int32_t` values mapped from [`of_error_t`]:
- `OF_OK` for success
- `OF_ERR_INVALID_ARG` for invalid pointers/inputs
- `OF_ERR_STATE` for lifecycle misuse or invalid runtime state
- `OF_ERR_IO`, `OF_ERR_DATA_QUALITY`, and other domain-specific failures
## Snapshot and Callback Payload Contracts
- `of_get_book_snapshot(...)` and `BOOK_SNAPSHOT` callbacks share the same JSON schema
- `of_get_derived_analytics_snapshot(...)` and `DERIVED_ANALYTICS` callbacks share the same JSON schema
- `of_get_session_candle_snapshot(...)` and `of_get_interval_candle_snapshot(...)` are additive snapshot families and do not alter the older analytics/signal contracts
- `inout_len` is both input capacity and output required size; if the buffer is too small, retry with the returned byte count
- payload field names are treated as stable once published; new fields are added additively
## Integration Notes
- Treat engine and subscription handles as opaque; do not cast or inspect internals.
- Keep ABI structs initialized (zero-init is recommended before setting fields).
- Prefer explicit timestamps and sequence numbers for external ingest to maximize quality checks.
- Snapshot functions write the required byte length back through `inout_len`; if the caller buffer is too small, retry with the returned size.
- `BOOK_SNAPSHOT` callbacks emit the same JSON shape as `of_get_book_snapshot(...)`, but only when book state changes for the subscribed symbol.
- `DERIVED_ANALYTICS` callbacks emit the same JSON shape as `of_get_derived_analytics_snapshot(...)`, but only when trade-driven analytics change for the subscribed symbol.
## Real-World Use Cases
### 1. Embed the runtime in a C or C++ trading host
Use the lifecycle, subscription, and polling APIs directly from a native host
process that already owns process supervision and deployment.
### 2. Drive Python or Java bindings from the same native ABI
The Python and Java packages both rely on this ABI, so host-side operators can
reason about one native contract instead of three unrelated APIs.
### 3. Build a custom host-side event pump
Use callbacks for snapshot/event delivery and poll-driven control for host-side
scheduling.
## Detailed Example: Poll And Read Snapshots
```c
#include "orderflow.h"
#include <stdint.h>
#include <stdio.h>
int main(void) {
of_engine_t* engine = NULL;
of_engine_config_t cfg = {0};
cfg.instance_id = "native-demo";
if (of_engine_create(&cfg, &engine) != OF_OK) return 1;
if (of_engine_start(engine) != OF_OK) return 2;
of_symbol_t symbol = {0};
symbol.venue = "SIM";
symbol.symbol = "ESM6";
symbol.depth_levels = 10;
if (of_subscribe(engine, &symbol, OF_STREAM_ANALYTICS, NULL, NULL, NULL) != OF_OK) return 3;
if (of_engine_poll_once(engine, OF_DQ_NONE) != OF_OK) return 4;
char buf[2048];
uint32_t len = (uint32_t)sizeof(buf);
if (of_get_analytics_snapshot(engine, &symbol, buf, &len) == OF_OK) {
printf("analytics: %.*s\n", (int)len, buf);
}
len = (uint32_t)sizeof(buf);
if (of_get_book_snapshot(engine, &symbol, buf, &len) == OF_OK) {
printf("book: %.*s\n", (int)len, buf);
}
of_engine_stop(engine);
of_engine_destroy(engine);
return 0;
}
```
- Prefer explicit timestamps and sequence numbers for external ingest to maximize quality checks.
- Snapshot functions write the required byte length back through `inout_len`; if the caller buffer is too small, retry with the returned size.
- `BOOK_SNAPSHOT` callbacks emit the same JSON shape as `of_get_book_snapshot(...)`, but only when book state changes for the subscribed symbol.
- `DERIVED_ANALYTICS` callbacks emit the same JSON shape as `of_get_derived_analytics_snapshot(...)`, but only when trade-driven analytics change for the subscribed symbol.