FerroMatch

Matching cycle

Command, match, event, journal: the FerroMatch execution loop.

The core loop is intentionally small: orders enter the book, the book returns deterministic match results, and the journal records durable status and trade entries without changing matching semantics.

use std::path::Path;
 
use ferromatch_core::{Order, OrderBook, OrderStatus, OrderType, Side, TimeInForce};
use ferromatch_journal::{EventJournal, JournalEntry};
 
let mut book = OrderBook::new("AAPL");
let mut journal = EventJournal::create(Path::new("session.fmj"), 1_024)?;
 
let orders = [
    Order::new(1, 185_000_000, 100, Side::Sell, OrderType::Limit, TimeInForce::GoodTilCancel, 0),
    Order::new(2, 185_000_000, 100, Side::Buy, OrderType::Limit, TimeInForce::GoodTilCancel, 0),
];
 
for order in orders {
    let submitted_id = order.id;
    let result = book.submit(order)?;
 
    let status_entry = JournalEntry::order_status(
        0,
        0,
        submitted_id,
        result.status as u8,
        result.remaining_quantity,
        0,
    );
    journal.append(&status_entry);
 
    for fill in &result.fills {
        let trade_entry = JournalEntry::trade(
            0,
            fill.timestamp,
            fill.taker_order_id,
            fill.maker_order_id,
            fill.price,
            fill.quantity,
            0,
        );
        journal.append(&trade_entry);
    }
}
 
assert_eq!(book.order_count(), 0);
# Ok::<(), Box<dyn std::error::Error>>(())

The journal is the contract between live matching, recovery, and replay. Consumers should depend on status and trade entries rather than inspecting book internals.