sequence-algo-sdk 0.4.0

Sequence Markets Algo SDK — write HFT trading algos in Rust, compile to WASM, deploy to Sequence
Documentation
//! WASM export macro for algo deployment.
//!
//! One macro — `export_algo!` — exports all capabilities. The runtime probes
//! which WASM exports exist and enables features accordingly:
//! - `algo_on_book_v3` → local book updates with OnlineFeatures
//! - `algo_on_nbbo` → cross-venue NBBO (enabled if export present)
//! - `algo_on_message` → mesh messaging (enabled if export present)
//! - `algo_on_heartbeat` → 1Hz heartbeat
//! - `algo_on_fill`, `algo_on_reject`, `algo_on_shutdown`, `algo_alloc`

/// Generate all WASM exports for your algo.
///
/// ```rust,ignore
/// struct MyAlgo { /* ... */ }
/// impl Algo for MyAlgo { /* ... */ }
/// export_algo!(MyAlgo { /* init */ });
/// ```
///
/// Override only the callbacks you need — defaults are no-ops:
/// - `on_book` — local venue book updates (always called)
/// - `on_nbbo` — cross-venue NBBO (enabled when overridden)
/// - `on_message` — mesh messaging from peers (enabled when overridden)
/// - `on_fill`, `on_reject` — order lifecycle events
/// - `on_shutdown` — cleanup before algo stops
/// - `on_heartbeat` — 1Hz tick with features
#[cfg(target_arch = "wasm32")]
#[macro_export]
macro_rules! export_algo {
    ($init:expr) => {
        extern crate alloc as _alloc;
        static mut ALGO: Option<_alloc::boxed::Box<dyn $crate::Algo>> = None;
        static mut ACTIONS: $crate::Actions = $crate::Actions::new();
        static mut WASM_OUT: $crate::WasmActions = $crate::WasmActions::new();

        #[inline(always)]
        fn init() {
            unsafe {
                if ALGO.is_none() {
                    ALGO = Some(_alloc::boxed::Box::new($init));
                }
            }
        }

        // ── Book update (always present) ─────────────────────────────────

        #[no_mangle]
        pub extern "C" fn algo_on_book_v3(book_ptr: u32, state_ptr: u32) -> u32 {
            init();
            unsafe {
                let book = &*(book_ptr as *const $crate::L2Book);
                let state = &*(state_ptr as *const $crate::AlgoState);
                let features =
                    &*($crate::ONLINE_FEATURES_WASM_OFFSET as *const $crate::OnlineFeatures);
                ACTIONS.clear();
                if let Some(algo) = ALGO.as_mut() {
                    algo.on_book(book, state, features, &mut ACTIONS);
                }
                WASM_OUT.from_actions(&ACTIONS);
                &WASM_OUT as *const _ as u32
            }
        }

        // ── Cross-venue NBBO (runtime detects this export) ───────────────

        #[no_mangle]
        pub extern "C" fn algo_on_nbbo(nbbo_ptr: u32, books_ptr: u32, state_ptr: u32) -> u32 {
            init();
            unsafe {
                let nbbo = &*(nbbo_ptr as *const $crate::NbboSnapshot);
                let books = &*(books_ptr as *const $crate::VenueBooks);
                let state = &*(state_ptr as *const $crate::AlgoState);
                let features =
                    &*($crate::ONLINE_FEATURES_WASM_OFFSET as *const $crate::OnlineFeatures);
                ACTIONS.clear();
                if let Some(algo) = ALGO.as_mut() {
                    algo.on_nbbo(nbbo, books, state, features, &mut ACTIONS);
                }
                WASM_OUT.from_actions(&ACTIONS);
                &WASM_OUT as *const _ as u32
            }
        }

        // ── Mesh messaging (runtime detects this export) ─────────────────

        #[no_mangle]
        pub extern "C" fn algo_on_message(
            from: u64,
            payload_ptr: u32,
            payload_len: u32,
            state_ptr: u32,
        ) -> u32 {
            init();
            unsafe {
                let payload = core::slice::from_raw_parts(
                    payload_ptr as *const u8,
                    payload_len as usize,
                );
                let state = &*(state_ptr as *const $crate::AlgoState);
                let mesh_table = &*($crate::messaging::MESH_TABLE_WASM_OFFSET
                    as *const $crate::messaging::MeshTable);
                let from_label = mesh_table.label_for(from);
                ACTIONS.clear();
                if let Some(algo) = ALGO.as_mut() {
                    algo.on_message(from_label, payload, state, &mut ACTIONS);
                }
                WASM_OUT.from_actions(&ACTIONS);
                &WASM_OUT as *const _ as u32
            }
        }

        // ── Heartbeat (1Hz) ──────────────────────────────────────────────

        #[no_mangle]
        pub extern "C" fn algo_on_heartbeat(state_ptr: u32) -> u32 {
            init();
            unsafe {
                let state = &*(state_ptr as *const $crate::AlgoState);
                let features =
                    &*($crate::ONLINE_FEATURES_WASM_OFFSET as *const $crate::OnlineFeatures);
                ACTIONS.clear();
                if let Some(algo) = ALGO.as_mut() {
                    algo.on_heartbeat(state, features, &mut ACTIONS);
                }
                WASM_OUT.from_actions(&ACTIONS);
                &WASM_OUT as *const _ as u32
            }
        }

        // ── Order lifecycle ──────────────────────────────────────────────

        #[no_mangle]
        pub extern "C" fn algo_on_fill(fill_ptr: u32, state_ptr: u32) {
            init();
            unsafe {
                let fill = &*(fill_ptr as *const $crate::Fill);
                let state = &*(state_ptr as *const $crate::AlgoState);
                if let Some(algo) = ALGO.as_mut() {
                    algo.on_fill(fill, state);
                }
            }
        }

        #[no_mangle]
        pub extern "C" fn algo_on_reject(reject_ptr: u32) {
            init();
            unsafe {
                let reject = &*(reject_ptr as *const $crate::Reject);
                if let Some(algo) = ALGO.as_mut() {
                    algo.on_reject(reject);
                }
            }
        }

        #[no_mangle]
        pub extern "C" fn algo_on_shutdown(state_ptr: u32) -> u32 {
            init();
            unsafe {
                let state = &*(state_ptr as *const $crate::AlgoState);
                ACTIONS.clear();
                if let Some(algo) = ALGO.as_mut() {
                    algo.on_shutdown(state, &mut ACTIONS);
                }
                WASM_OUT.from_actions(&ACTIONS);
                &WASM_OUT as *const _ as u32
            }
        }

        // ── Memory allocator ─────────────────────────────────────────────

        #[no_mangle]
        pub extern "C" fn algo_alloc(size: u32) -> u32 {
            let layout = core::alloc::Layout::from_size_align(size as usize, 8).unwrap();
            unsafe { _alloc::alloc::alloc(layout) as u32 }
        }
    };
}

/// Stub macro for native builds (no-op).
#[cfg(not(target_arch = "wasm32"))]
#[macro_export]
macro_rules! export_algo {
    ($init:expr) => {};
}