| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "engine/SimplxShim.hpp" |
| #include "common/Book.hpp" |
| #include "recovery/RecoveryProxy.hpp" |
| #include "iaca/Fragment.hpp" |
| #include "iaca/IacaAggregator.hpp" |
| #include <iostream> |
|
|
| using namespace eunex; |
| using namespace eunex::recovery; |
| using namespace eunex::iaca; |
|
|
| int main() { |
| std::cout << "=== Simple Match with Recovery + IACA ===\n\n"; |
|
|
| |
| FragmentStore store; |
| RecoveryProxy recoveryProxy(ORIGIN_BOOK, 1, store, true); |
| IacaAggregator aggregator; |
|
|
| int iaMessagesGenerated = 0; |
| aggregator.registerHandler(std::make_shared<NewOrderHandler>( |
| [&](const FragmentChain& chain) { |
| ++iaMessagesGenerated; |
| std::cout << " [IACA] IA message generated from chain " |
| << chain.chainId << " (" << chain.fragments.size() |
| << " fragments)\n"; |
| } |
| )); |
|
|
| Book book(1); |
|
|
| |
| std::cout << "ββ Processing SELL 100 @ 50.00 ββ\n"; |
| { |
| Order sellOrder{}; |
| sellOrder.clOrdId = 1001; |
| sellOrder.symbolIdx = 1; |
| sellOrder.side = Side::Sell; |
| sellOrder.ordType = OrderType::Limit; |
| sellOrder.tif = TimeInForce::Day; |
| sellOrder.price = toFixedPrice(50.00); |
| sellOrder.quantity = 100; |
|
|
| |
| recoveryProxy.cause(1, sellOrder, |
| [&](uint64_t chainId, uint64_t seq) -> int { |
|
|
| |
| IacaFragment bookFrag{}; |
| bookFrag.chainId = chainId; |
| bookFrag.origin = {ORIGIN_BOOK, 1, seq}; |
| bookFrag.previousOrigin = Origin::null(); |
| bookFrag.causeId = CAUSE_NEW_ORDER_SELL; |
| bookFrag.nextCount = 1; |
|
|
| |
| book.newOrder(sellOrder, |
| [](const Trade&) {}, |
| [](const ExecutionReport& rpt) { |
| std::cout << " [ExecRpt] Status=" |
| << (int)rpt.status << " Remaining=" |
| << rpt.remainingQty << "\n"; |
| } |
| ); |
|
|
| |
| recoveryProxy.effect([&]() { |
| IacaFragment ackFrag{}; |
| ackFrag.chainId = chainId; |
| ackFrag.origin = {ORIGIN_LOGICAL_CORE, 1, seq}; |
| ackFrag.previousOrigin = bookFrag.origin; |
| ackFrag.causeId = CAUSE_ACK_DATA; |
| ackFrag.nextCount = 0; |
| aggregator.addFragment(ackFrag); |
| std::cout << " [Effect] Ack sent (Master)\n"; |
| }); |
|
|
| aggregator.addFragment(bookFrag); |
| return 0; |
| } |
| ); |
| } |
|
|
| |
| std::cout << "\nββ Processing BUY 60 @ 50.00 ββ\n"; |
| { |
| Order buyOrder{}; |
| buyOrder.clOrdId = 1002; |
| buyOrder.symbolIdx = 1; |
| buyOrder.side = Side::Buy; |
| buyOrder.ordType = OrderType::Limit; |
| buyOrder.tif = TimeInForce::Day; |
| buyOrder.price = toFixedPrice(50.00); |
| buyOrder.quantity = 60; |
|
|
| recoveryProxy.cause(2, buyOrder, |
| [&](uint64_t chainId, uint64_t seq) -> int { |
|
|
| IacaFragment bookFrag{}; |
| bookFrag.chainId = chainId; |
| bookFrag.origin = {ORIGIN_BOOK, 1, seq}; |
| bookFrag.previousOrigin = Origin::null(); |
| bookFrag.causeId = CAUSE_NEW_ORDER_BUY; |
| bookFrag.nextCount = 2; |
|
|
| book.newOrder(buyOrder, |
| [&](const Trade& trade) { |
| std::cout << " [Trade] " << trade.quantity |
| << " @ " << toDouble(trade.price) << "\n"; |
|
|
| |
| recoveryProxy.effect([&]() { |
| IacaFragment tradeFrag{}; |
| tradeFrag.chainId = chainId; |
| tradeFrag.origin = {ORIGIN_LOGICAL_CORE, 1, seq + 100}; |
| tradeFrag.previousOrigin = bookFrag.origin; |
| tradeFrag.causeId = CAUSE_TRADE_DATA; |
| tradeFrag.nextCount = 0; |
| aggregator.addFragment(tradeFrag); |
| }); |
| }, |
| [](const ExecutionReport& rpt) { |
| std::cout << " [ExecRpt] Status=" |
| << (int)rpt.status << " Filled=" |
| << rpt.filledQty << "\n"; |
| } |
| ); |
|
|
| recoveryProxy.effect([&]() { |
| IacaFragment ackFrag{}; |
| ackFrag.chainId = chainId; |
| ackFrag.origin = {ORIGIN_LOGICAL_CORE, 1, seq + 200}; |
| ackFrag.previousOrigin = bookFrag.origin; |
| ackFrag.causeId = CAUSE_ACK_DATA; |
| ackFrag.nextCount = 0; |
| aggregator.addFragment(ackFrag); |
| }); |
|
|
| aggregator.addFragment(bookFrag); |
| return 0; |
| } |
| ); |
| } |
|
|
| |
| std::cout << "\nββ Summary βββββββββββββββββββββββββββββββ\n"; |
| std::cout << " Recovery fragments persisted: " << store.size() << "\n"; |
| std::cout << " IACA chains completed: " << aggregator.completedChainCount() << "\n"; |
| std::cout << " IA messages generated: " << iaMessagesGenerated << "\n"; |
| std::cout << " Book state: " << book.bidCount() << " bids, " |
| << book.askCount() << " asks\n"; |
|
|
| auto bids = book.getBids(5); |
| auto asks = book.getAsks(5); |
| if (!asks.empty()) { |
| std::cout << " Best ask: " << toDouble(asks[0].price) |
| << " x " << asks[0].totalQty << "\n"; |
| } |
| if (!bids.empty()) { |
| std::cout << " Best bid: " << toDouble(bids[0].price) |
| << " x " << bids[0].totalQty << "\n"; |
| } |
|
|
| |
| std::cout << "\nββ Mirror Replay Simulation ββββββββββββββ\n"; |
| RecoveryProxy mirrorProxy(ORIGIN_BOOK, 1, store, false); |
| Book mirrorBook(1); |
|
|
| |
| mirrorProxy.effect([]() { |
| std::cout << " [BUG] This should not print on Mirror!\n"; |
| }); |
| std::cout << " Mirror effect correctly skipped.\n"; |
|
|
| |
| mirrorProxy.recoveryEffect([]() { |
| std::cout << " [RecoveryEffect] Mirror-only logic executed.\n"; |
| }); |
|
|
| std::cout << "\n=== Complete ===\n"; |
| return 0; |
| } |
|
|