{"repo":"Shivfun99/Pulse-Order","free":true,"listed":false,"github":"https://github.com/Shivfun99/Pulse-Order","clone":"git clone https://github.com/Shivfun99/Pulse-Order.git","description":"C++17 low-latency trading engine with DPDK packet path,  order book, risk checks, order encoding, and nanosecond/microsecond latency benchmarks.","language":"C++","stars":121,"topics":["cmake","cpp","dpdk","hft","kernel","linux","networking","orderbook","systems-programming","trading"],"license":"MIT","category":"hft_engine","readme_excerpt":"# PulseBook\n![Stars](https://img.shields.io/github/stars/Shivfun99/Pulse-Order?style=for-the-badge)\n\n**PulseBook** is a C++20 + DPDK low-latency trading packet processor.\n\nIt takes compact Ethernet-style market-data packets, updates an in-memory L2 order book, runs a simple imbalance strategy, applies risk checks, and emits outbound order packets through DPDK-style RX/TX paths.\n\nThis project is mainly about learning and proving the **trading engine hot path**:\n\n```text\nmarket-data packet\n    -> decode\n    -> L2 book update\n    -> strategy decision\n    -> risk check\n    -> order encode\n    -> TX enqueue\n```\n\nIt is **not** claiming exchange latency or physical NIC wire latency.\n\n---\n\n## Why I built this\n\nI wanted to understand what actually matters in a low-latency trading path.\n\nInstead of building a big backend system with APIs, databases, queues, dashboards, etc., I kept the hot path small:\n\n- fixed-size binary packets\n- integer price ticks\n- fixed-memory order book\n- preallocated order handling\n- no logging/allocation inside the measured path\n- DPDK RX/TX style processing\n\nThe goal of V1 is to validate the packet-processing engine before moving to real NIC hardware and real market-data replay.\n\n---\n\n## Current status\n\n| Area | Status |\n|---|---|\n| C++20 trading engine | Done |\n| Fixed binary market/order protocol | Done |\n| 62-byte Ethernet frame encode/decode | Done |\n| L2 order book | Done |\n| BUY / SELL / NO_SIGNAL logic | Done |\n| Inline risk checks | Done |\n| DPDK Ring PMD virtual path | Done |\n| DPDK AF_PACKET over private Linux `veth` | Done |\n| Real supported NIC / VFIO benchmark | Not done yet |\n| Real market-data replay under burst load | Future work |\n\n---\n\n## Architecture\n\n```text\nInbound Ethernet market-data frame\n        |\n        v\nDPDK RX / rte_mbuf\n        |\n        v\nFixed binary decoder\n        |\n        v\nMarketUpdate\n        |\n        v\nTradingEngine\n   ┌────────────┬──────────────┬────────────┐\n   v            v              v\nL2 Order Book   Strategy       Risk Guard\n        |\n        v\nPreallocated order path\n        |\n        v\nOutbound order frame encoder\n        |\n        v\nDPDK TX enqueue\n```\n\n---\n\n## What the strategy does\n\nThis is intentionally simple for V1.\n\nThe engine keeps visible bid/ask liquidity in an L2 book.\n\n```text\nMore bid pressure  -> BUY\nMore ask pressure  -> SELL\nBalanced book      -> NO_SIGNAL\nRisk limit hit     -> RISK_REJECT\nBad packet         -> INVALID_FRAME\n```\n\nThis is not meant to be a profitable strategy. It is a controlled workload for testing the packet path.\n\n---\n\n## Performance results\n\nAll results below are from controlled synthetic workloads with fixed-size packets.\n\nThey are useful as **engine and packet-path microbenchmarks**, not as real market-burst p99 or exchange latency.\n\n### 1. Virtual DPDK Ring PMD path\n\nMeasured boundary:\n\n```text\nafter rte_eth_rx_burst() returned packet\n    -> decode / book / strategy / risk / encode\n    -> rte_eth_tx_burst() accepted order\n```\n\n| Core | p50 | p95 | p99 | p99.9 | Events | Failures |\n|---:|---:|---:|---:|---:|---:|---:|\n| CPU 0 | 110.844 ns | 248.397 ns | 552.217 ns | 706.464 ns | 1,000,000 | 0 |\n| CPU 2 | 112.847 ns | 254.407 ns | 550.214 ns | 754.541 ns | 1,000,000 | 0 |\n\nClassification:\n\n```text\nVirtual DPDK Ring PMD application-side RX-to-TX order-generation latency.\n```\n\n### 2. Kernel-backed DPDK AF_PACKET over private `veth`\n\nTopology:\n\n```text\nLinux raw generator on pb_peer\n    -> private veth pair\n    -> pb_eng\n    -> DPDK AF_PACKET RX\n    -> PulseBook engine\n    -> DPDK AF_PACKET TX\n    -> generator validates returned order\n```\n\nMeasured boundary:\n\n```text\nafter AF_PACKET rte_eth_rx_burst() returned packet\n    -> decode / book / strategy / risk / encode\n    -> AF_PACKET rte_eth_tx_burst() accepted order\n```\n\n| Core | p50 | p95 | p99 | p99.9 | Events | Failures |\n|---:|---:|---:|---:|---:|---:|---:|\n| CPU 0 | 1.737 µs | 2.594 µs | 3.262 µs | 10.542 µs | 1,000,000 | 0 |\n| CPU 2 | 1.832 µs | 2.903 µs | 7.822 µs | 22.061 µs | 1,000,000 | 0 |\n\nClassification:\n\n```text\nKernel-backed DPDK AF_PACKET application-side RX-to-TX-enqueue latency over Linux veth.\n```\n\n---\n\n## Important measurement note\n\nThese numbers do **not** include:\n\n- real physical NIC ingress/egress\n- switch latency\n- hardware timestamping\n- exchange round-trip time\n- real market-data burst queueing\n- production feed handler behavior\n\nThey measure the application processing region only.\n\nFor real trading-style p99, the next step is replaying high-rate market data with bursts and measuring queue buildup/tail latency.\n\n---\n\n## Main design decisions\n\nWhat mattered most:\n\n- fixed-size binary frames instead of JSON/variable messages\n- integer ticks instead of floating-point prices\n- fixed-depth order book\n- preallocated order/outbox memory\n- no heap allocation in the hot path\n- no logging/string formatting in the measured loop\n- single-core run-to-completion design\n- separate measurements for Ring PMD and AF_PACKET\n\nWhat did not matter much yet:\n\n- complex strategy logic\n- multi-threading\n- databases\n- REST APIs\n- dashboards\n- Kafka/Redis/Docker\n- physical NIC tuning, because V1 does not have a supported wired NIC path yet\n\n---\n\n## Hardware note\n\nThis laptop does not have a suitable wired PCIe Ethernet NIC for a true DPDK/VFIO physical benchmark.\n\nDetected network hardware:\n\n- Realtek PCIe Wi-Fi adapter\n- USB RNDIS phone tethering\n\nSo V1 uses:\n\n- DPDK Ring PMD for a clean virtual DPDK baseline\n- DPDK AF_PACKET over a private Linux `veth` pair for a kernel-backed interface path\n\nA real NIC benchmark is future work.\n\n---\n\n## Repository layout\n\n```text\n.\n├── apps/\n│   ├── pulsebook_dpdk_scenarios.cpp\n│   ├── pulsebook_dpdk_latency_benchmark.cpp\n│   ├── pulsebook_dpdk_regime_benchmark.cpp\n│   ├── pulsebook_dpdk_afpacket_engine.cpp\n│   ├── pulsebook_afpacket_generator.cpp\n│   ├── pulsebook_dpdk_afpacket_latency.cpp\n│   └── pulsebook_afpacket_benchmark_generator.cpp\n├── include/pulsebook/\n│   ├── book/\n│   ├── common/\n│   ├── dpdk/\n│   ├── engine/\n│   ├── order/\n│   ├── risk/\n│   ├── strategy/\n│   └── wire/\n├── tests/\n├── scripts/level3/\n├── docs/level3/\n├── results/level3/\n├── CMakeLists.txt\n├── real_run.md\n└── details.md\n```\n\n---\n\n## Requirements\n\nTested on:\n\n```text\nUbuntu 26.04\nC++20\nCMake\nNinja\nDPDK 25.11.0\nGCC 15.2.0\n```\n\nInstall common build tools:\n\n```bash\nsudo apt update\nsudo apt install -y build-essential cmake ninja-build pkg-config dpdk dpdk-dev libdpdk-dev\n```\n\nCheck DPDK:\n\n```bash\npkg-config --modversion libdpdk\n\nfind /usr/lib/x86_64-linux-gnu \\\n    \\( -name 'librte_net_ring.so*' -o -name 'librte_net_af_packet.so*' \\) \\\n    -print 2>/dev/null | sort\n```\n\n---\n\n## Build\n\n```bash\ncmake -S . -B build-dpdk \\\n    -G Ninja \\\n    -DCMAKE_BUILD_TYPE=Release \\\n    -DBUILD_TESTING=ON \\\n    -DPULSEBOOK_ENABLE_DPDK=ON \\\n    -DPULSEBOOK_BUILD_BENCHMARKS=ON\n\ncmake --build build-dpdk -j\"$(nproc)\"\n```\n\n---\n\n## Run tests\n\n```bash\nctest --test-dir build-dpdk --output-on-failure\n```\n\nExpected:\n\n```text\n100% tests passed\n```\n\n---\n\n## Run Ring PMD scenario validation\n\n```bash\n./build-dpdk/pulsebook_dpdk_scenarios \\\n    -l 0 \\\n    --no-pci \\\n    --no-huge \\\n    --in-memory \\\n    --mbuf-pool-ops-name=ring_mp_mc \\\n    --file-prefix=pb_scenarios\n```\n\nThis validates:\n\n```text\nNO_SIGNAL\nBUY\nSELL\nRISK_REJECT\nINVALID_FRAME\n```\n\n---\n\n## Run Ring PMD latency benchmark\n\nCPU 0:\n\n```bash\n./build-dpdk/pulsebook_dpdk_latency_benchmark \\\n    -l 0 \\\n    --no-pci \\\n    --no-huge \\\n    --in-memory \\\n    --mbuf-pool-ops-name=ring_mp_mc \\\n    --file-prefix=pb_ring_c0\n```\n\nCPU 2:\n\n```bash\n./build-dpdk/pulsebook_dpdk_latency_benchmark \\\n    -l 2 \\\n    --no-pci \\\n    --no-huge \\\n    --in-memory \\\n    --mbuf-pool-ops-name=ring_mp_mc \\\n    --file-prefix=pb_ring_c2\n```\n\n---\n\n## Run AF_PACKET functional test\n\nCreate the private test link:\n\n```bash\n./scripts/level3/setup_veth_afpacket.sh\n```\n\nTerminal 1 — engine:\n\n```bash\nAF_PACKET_LIB=\"$(find /usr/lib/x86_64-linux-gnu \\\n    -name 'librte_net_af_packet.so' \\\n    -print 2>/dev/null | head -n 1)\"\n\nsudo ./build-dpdk/pulsebook_dpdk_afpacket_engine \\\n    -l 0 \\\n    --no-pci \\\n    --no-huge \\\n    --in-memory \\\n    --mbuf-pool-ops-name=ring_mp_mc \\\n    -d \"${AF_PACKET_LIB}\" \\\n    --vdev='eth_af_packet0,iface=pb_eng,qpairs=1,qdisc_bypass=1' \\\n    --file-prefix=pb_af_func\n```\n\nTerminal 2 — generator:\n\n```bash\nsudo ./build-dpdk/pulsebook_afpacket_generator pb_peer\n```\n\nExpected generator result:\n\n```text\nMarket packets sent:       11\nOutbound orders received:  1\nGenerated order side:      BUY\nStatus:                    OK\n```\n\nClean up after AF_PACKET runs:\n\n```bash\n./scripts/level3/remove_veth_afpacket.sh\n```\n\n---\n\n## Run AF_PACKET latency benchmark\n\nCreate the private test link first:\n\n```bash\n./scripts/level3/setup_veth_afpacket.sh\n```\n\nCPU 0 engine:\n\n```bash\nAF_PACKET_LIB=\"$(find /usr/lib/x86_64-linux-gnu \\\n    -name 'librte_net_af_packet.so' \\\n    -print 2>/dev/null | head -n 1)\"\n\nsudo ./build-dpdk/pulsebook_dpdk_afpacket_latency \\\n    -l 0 \\\n    --no-pci \\\n    --no-huge \\\n    --in-memory \\\n    --mbuf-pool-ops-name=ring_mp_mc \\\n    -d \"${AF_PACKET_LIB}\" \\\n    --vdev='eth_af_packet0,iface=pb_eng,qpairs=1,qdisc_bypass=1' \\\n    --file-prefix=pb_aflat_c0\n```\n\nIn another terminal:\n\n```bash\nsudo ./build-dpdk/pulsebook_afpacket_benchmark_generator pb_peer\n```\n\nFor CPU 2, repeat the engine command with:\n\n```bash\n-l 2\n--file-prefix=pb_aflat_c2\n```\n\nThen clean up:\n\n```bash\n./scripts/level3/remove_veth_afpacket.sh\n```\n\n---\n\n## Useful run guides\n\n- `real_run.md` — exact step-by-step commands\n- `details.md` — full project explanation, architecture and claims\n- `docs/level3/` — design notes and benchmark scope\n- `results/level3/` — saved successful output logs\n\n---\n\n## What this project is good for\n\nPulseBook V1 is good for showing:\n\n- low-level C++ systems programming\n- DPDK RX/TX integration\n- packet decoding/encoding\n- latency-aware design\n- benchmark honesty\n- risk-aware trading-engine structure\n- debugging real systems issues like PMD linking, mbuf","default_branch":"main","files":136,"tree":[".github/workflows/clone.yml",".gitignore",".vscode/c_cpp_properties.json","CLONE.md","CMakeLists.txt","LICENSE","README.md","apps/pulsebook_afpacket_benchmark_generator.cpp","apps/pulsebook_afpacket_generator.cpp","apps/pulsebook_dpdk_afpacket_engine.cpp","apps/pulsebook_dpdk_afpacket_latency.cpp","apps/pulsebook_dpdk_latency_benchmark.cpp","apps/pulsebook_dpdk_regime_benchmark.cpp","apps/pulsebook_dpdk_ring_test.cpp","apps/pulsebook_dpdk_scenarios.cpp","build-dpdk/.ninja_deps","build-dpdk/.ninja_log","build-dpdk/CMakeCache.txt","build-dpdk/CMakeFiles/4.2.3/CMakeCXXCompiler.cmake","build-dpdk/CMakeFiles/4.2.3/CMakeDetermineCompilerABI_CXX.bin","build-dpdk/CMakeFiles/4.2.3/CMakeSystem.cmake","build-dpdk/CMakeFiles/4.2.3/CompilerIdCXX/CMakeCXXCompilerId.cpp","build-dpdk/CMakeFiles/4.2.3/CompilerIdCXX/a.out","build-dpdk/CMakeFiles/CMakeConfigureLog.yaml","build-dpdk/CMakeFiles/CTestScript.cmake","build-dpdk/CMakeFiles/InstallScripts.json","build-dpdk/CMakeFiles/TargetDirectories.txt","build-dpdk/CMakeFiles/cmake.check_cache","build-dpdk/CMakeFiles/pulsebook_afpacket_generator.dir/apps/pulsebook_afpacket_generator.cpp.o","build-dpdk/CMakeFiles/pulsebook_dpdk_afpacket_engine.dir/apps/pulsebook_dpdk_afpacket_engine.cpp.o","build-dpdk/CMakeFiles/pulsebook_dpdk_regime_benchmark.dir/apps/pulsebook_dpdk_regime_benchmark.cpp.o","build-dpdk/CMakeFiles/pulsebook_dpdk_scenarios.dir/apps/pulsebook_dpdk_scenarios.cpp.o","build-dpdk/CMakeFiles/pulsebook_test_engine_scenarios.dir/tests/test_engine_scenarios.cpp.o","build-dpdk/CMakeFiles/pulsebook_test_engine_wire_adapter.dir/tests/test_engine_wire_adapter.cpp.o","build-dpdk/CMakeFiles/pulsebook_test_ethernet_market_frame.dir/tests/test_ethernet_market_frame.cpp.o","build-dpdk/CMakeFiles/pulsebook_test_ethernet_order_frame.dir/tests/test_ethernet_order_frame.cpp.o","build-dpdk/CMakeFiles/pulsebook_test_wire_invalid_packet.dir/tests/test_wire_invalid_packet.cpp.o","build-dpdk/CMakeFiles/pulsebook_test_wire_market_data.dir/tests/test_wire_market_data.cpp.o","build-dpdk/CMakeFiles/pulsebook_test_wire_order.dir/tests/test_wire_order.cpp.o","build-dpdk/CMakeFiles/rules.ninja","build-dpdk/CTestTestfile.cmake","build-dpdk/DartConfiguration.tcl","build-dpdk/Testing/Temporary/CTestCostData.txt","build-dpdk/Testing/Temporary/LastTest.log","build-dpdk/build.ninja","build-dpdk/cmake_install.cmake","build-dpdk/pulsebook_afpacket_generator","build-dpdk/pulsebook_dpdk_afpacket_engine","build-dpdk/pulsebook_dpdk_regime_benchmark","build-dpdk/pulsebook_dpdk_scenarios","build-dpdk/pulsebook_test_engine_scenarios","build-dpdk/pulsebook_test_engine_wire_adapter","build-dpdk/pulsebook_test_ethernet_market_frame","build-dpdk/pulsebook_test_ethernet_order_frame","build-dpdk/pulsebook_test_wire_invalid_packet","build-dpdk/pulsebook_test_wire_market_data","build-dpdk/pulsebook_test_wire_order","details.md","docs/level3/ARCHITECTURE.md","docs/level3/BENCHMARK_METHOD.md","docs/level3/FINAL_RESULTS.md","docs/level3/LATENCY_BENCHMARK.md","docs/level3/REGIME_BENCHMARK.md","docs/level3/WIRE_PROTOCOL.md","include/pulsebook/bench/cpu_affinity.hpp","include/pulsebook/bench/latency_recorder.hpp","include/pulsebook/bench/rdtscp_clock.hpp","include/pulsebook/book/fixed_l2_book.hpp","include/pulsebook/common/constants.hpp","include/pulsebook/common/types.hpp","include/pulsebook/dpdk/dpdk_config.hpp","include/pulsebook/dpdk/dpdk_environment.hpp","include/pulsebook/dpdk/dpdk_latency_recorder.hpp","include/pulsebook/dpdk/dpdk_packet_io.hpp","include/pulsebook/dpdk/dpdk_port.hpp","include/pulsebook/dpdk/dpdk_run_loop.hpp","include/pulsebook/dpdk/engine_wire_adapter.hpp","include/pulsebook/dpdk/latency_virtual_link.hpp","include/pulsebook/dpdk/virtual_link.hpp","include/pulsebook/engine/trading_engine.hpp","include/pulsebook/order/order_encoder.hpp","include/pulsebook/order/order_request.hpp","include/pulsebook/order/preallocated_outbox.hpp","include/pulsebook/replay/realistic_replay_feed.hpp","include/pulsebook/replay/synthetic_feed.hpp","include/pulsebook/risk/risk_guard.hpp","include/pulsebook/strategy/imbalance_strategy.hpp","include/pulsebook/wire/endian.hpp","include/pulsebook/wire/ethernet_frame.hpp","include/pulsebook/wire/market_data_decoder.hpp","include/pulsebook/wire/market_data_packet.hpp","include/pulsebook/wire/order_packet.hpp","include/pulsebook/wire/order_packet_encoder.hpp","include/pulsebook/wire/wire_constants.hpp","include/pulsebook/wire/wire_header.hpp","pulsebook_dpdk_hello","results/level3/afpacket_engine_fixed.txt","results/level3/afpacket_generator_fixed.txt","results/level3/afpacket_latency_cpu0.txt","results/level3/afpacket_latency_cpu2.txt","results/level3/generator_cpu0.txt","results/level3/generator_cpu2.txt","results/level3/latency_cpu0.txt","results/level3/latency_cpu2.txt","results/level3/regime_cpu0.txt","results/level3/regime_cpu2.txt","scripts/level3/bind_vfio.sh","scripts/level3/dpdk_status.sh","scripts/level3/phase0_verify.sh","scripts/level3/phase9_hardware_readiness.sh","scripts/level3/remove_veth_afpacket.sh","scripts/level3/restore_kernel_driver.sh","scripts/level3/setup_hugepages.sh","scripts/level3/setup_veth_afpacket.sh","scripts/level3/show_dpdk_devices.sh","src/dpdk/dpdk_environment.cpp","src/dpdk/dpdk_packet_io.cpp","src/dpdk/dpdk_port.cpp","src/dpdk/dpdk_run_loop.cpp","tests/test_bench.cpp","tests/test_book.cpp","tests/test_dpdk_engine_adapter.cpp","tests/test_engine.cpp","tests/test_engine_scenarios.cpp","tests/test_engine_wire_adapter.cpp","tests/test_ethernet_market_frame.cpp","tests/test_ethernet_order_frame.cpp","tests/test_order.cpp","tests/test_replay.cpp","tests/test_risk.cpp","tests/test_smoke.cpp","tests/test_strategy.cpp","tests/test_wire_invalid_packet.cpp","tests/test_wire_market_data.cpp","tests/test_wire_order.cpp","upcoming_version.md"],"storefront":"/r/Shivfun99","claimed":false,"request_supported":{"post":"https://gitbuyer.com/r/Shivfun99/Pulse-Order/request-supported","requests":0},"note":"indexed from public GitHub; nothing is for sale on this page. Clone it from GitHub. Paid listings live at /search."}