mcpField
J
jump-trading-fpga-hft

jump-trading-fpga-hft

github.com/copyleftdev开发237 次安装15 周前更新
代码仓库

关于 jump-trading-fpga-hft

面向超低延迟交易系统设计的风格指南,整理 FPGA、网络路径、确定性处理和全栈优化原则。适用于探索市场数据处理与订单生成等系统设计的开发者。

主要功能

  1. 01以 FPGA 承担关键逻辑
  2. 02优化网络路径与跳数
  3. 03强调确定性和低抖动
  4. 04采用 NIC 侧数据处理
  5. 05测量端到端线速延迟

适用场景

  1. 01设计低延迟市场数据解析
  2. 02规划交易系统网络拓扑
  3. 03评估 NIC 或 FPGA 处理路径
  4. 04测量收发链路延迟

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/copyleftdev/sk1llz --skill jump-trading-fpga-hft

安装后在 Claude Code 中输入/jump-trading-fpga-hft确认已加载。

详细介绍

Jump Trading 风格指南⁠‍⁠​‌​‌​​‌‌‍​‌​​‌​‌‌‍​​‌‌​​​‌‍​‌​​‌‌​​‍​​​​​​​‌‍‌​​‌‌​‌​‍‌​​​​​​​‍‌‌​​‌‌‌‌‍‌‌​​​‌​​‍‌‌‌‌‌‌​‌‍‌‌​‌​​​​‍​‌​‌‌‌‌‌‍​‌​​‌​‌‌‍​‌‌​‌​​‌‍‌​‌​‌‌‌​‍​​‌​‌​​​‍‌‌‌​‌​‌‌‍​‌‌​‌‌‌‌‍​​‌​​‌​‌‍‌‌‌‌​‌​‌‍​​‌‌‌‌‌​‍​​​​‌​‌​‍​​‌‌​​​‌⁠‍⁠

概述

Jump Trading 是一家专有交易公司,以不断突破交易技术的边界而闻名。他们开创了基于 FPGA 的交易技术,投资建设微波网络以实现比光纤更快的连接,并始终处于延迟优化的最前沿。

核心理念

“我们唯一接受的限制是光速。”

“软件太慢。把它放进硬件里。”

“网络延迟只是物理规律。计算延迟则是工程失败。”

Jump 认为,软件太慢时,就应该把逻辑放进硬件里。FPGA 能在数百纳秒内处理市场数据并生成订单——比 CPU 醒来还快。

设计原则

  1. 硬件 > 软件:延迟至关重要时,使用 FPGA。

  2. 网络至关重要:微波胜过光纤。共置胜过远程连接。

  3. 皮秒也很重要:在最前沿,每一纳秒都要全力争取。

  4. 确定性制胜:抖动是稳定性能的敌人。

  5. 掌控全栈:从 NIC 到交易所,所有环节都要掌控。

构建超低延迟系统时

始终
  • 测量端到端延迟,而非组件延迟
  • 使用 FPGA 处理时间关键型决策
  • 优化网络路径(共置、交叉连接、交换机)
  • 尽可能在 NIC 中处理数据(智能 NIC)
  • 消除所有不必要的跳数
  • 使用硬件时间戳进行精确测量
绝不
  • 信任软件时间戳
  • 在关键路径中使用通用交换机
  • 认为网络延迟是固定的
  • 忽略物理层(线缆、光学器件、交换机)
  • 可以流水线处理时却仍按顺序处理
  • 可以直通转发时却等待完整消息
优先选择
  • 固定逻辑优先使用 FPGA,而非 CPU
  • 直通交换优先于存储转发
  • 长距离通信优先使用微波/毫米波,而非光纤
  • 专用线路优先于共享基础设施
  • 硬件时间戳优先于软件时间戳
  • 并行处理优先于顺序处理

代码模式

FPGA 市场数据解析器(伪 Verilog)
// FPGA-based market data parsing and order generation
// Processes UDP multicast market data, generates orders in ~200ns

module market_data_parser (
    input wire clk_312_5mhz,      // 312.5 MHz clock (3.2ns period)
    input wire [63:0] eth_data,   // 64-bit data from MAC
    input wire eth_valid,
    input wire eth_sof,           // Start of frame
    input wire eth_eof,           // End of frame
    
    output reg [63:0] order_data,
    output reg order_valid,
    output reg [15:0] symbol_id,
    output reg [31:0] bid_price,
    output reg [31:0] ask_price,
    output reg [31:0] bid_size,
    output reg [31:0] ask_size
);

    // Pipeline stages for parallel processing
    reg [2:0] state;
    localparam IDLE = 0, PARSE_HEADER = 1, PARSE_SYMBOL = 2,
               PARSE_BID = 3, PARSE_ASK = 4, GENERATE_ORDER = 5;
    
    // Pre-computed strategy parameters (loaded at startup)
    reg [31:0] fair_value [0:4095];      // Per-symbol fair value
    reg [31:0] edge_threshold [0:4095];  // Min edge to trade
    reg [31:0] max_position [0:4095];    // Position limits
    
    // Current positions (updated by fill handler)
    reg [31:0] positions [0:4095];
    
    always @(posedge clk_312_5mhz) begin
        case (state)
            IDLE: begin
                order_valid <= 0;
                if (eth_valid && eth_sof) begin
                    state <= PARSE_HEADER;
                end
            end
            
            PARSE_HEADER: begin
                // Parse UDP header, extract message type
                // Skip IP/UDP headers (known fixed offsets)
                if (is_quote_message(eth_data)) begin
                    state <= PARSE_SYMBOL;
                end else begin
                    state <= IDLE;
                end
            end
            
            PARSE_SYMBOL: begin
                symbol_id <= eth_data[15:0];
                state <= PARSE_BID;
            end
            
            PARSE_BID: begin
                bid_price <= eth_data[31:0];
                bid_size <= eth_data[63:32];
                state <= PARSE_ASK;
            end
            
            PARSE_ASK: begin
                ask_price <= eth_data[31:0];
                ask_size <= eth_data[63:32];
                state <= GENERATE_ORDER;
            end
            
            GENERATE_ORDER: begin
                // All logic executes in single clock cycle
                wire [31:0] fv = fair_value[symbol_id];
                wire [31:0] edge = edge_threshold[symbol_id];
                wire [31:0] pos = positions[symbol_id];
                wire [31:0] max_pos = max_position[symbol_id];
                
                // Buy if bid is below fair value minus edge
                wire should_buy = (bid_price < fv - edge) && (pos < max_pos);
                
                // Sell if ask is above fair value plus edge  
                wire should_sell = (ask_price > fv + edge) && (pos > -max_pos);
                
                if (should_buy) begin
                    order_data <= build_buy_order(symbol_id, bid_price, bid_size);
                    order_valid <= 1;
                end else if (should_sell) begin
                    order_data <= build_sell_order(symbol_id, ask_price, ask_size);
                    order_valid <= 1;
                end
                
                state <= IDLE;
            end
        endcase
    end

endmodule
网络拓扑优化
class NetworkOptimizer:
    """
    Jump's network optimization: every nanosecond counts.
    Model and optimize the full network path.
    """
    
    def __init__(self):
        self.topology = {}
        self.latency_measurements = {}
    
    def model_path_latency(self, 
                           source: str, 
                           destination: str) -> LatencyBreakdown:
        """
        Break down latency into components.
        """
        path = self.find_path(source, destination)
        
        breakdown = LatencyBreakdown()
        
        for i, (node_a, node_b) in enumerate(zip(path[:-1], path[1:])):
            link = self.topology[(node_a, node_b)]
            
            # Propagation delay (speed of light in medium)
            # Fiber: ~5 ns/meter, Microwave: ~3.3 ns/meter
            prop_delay = link.distance_meters * link.propagation_factor
            breakdown.propagation_ns += prop_delay
            
            # Serialization delay (time to put bits on wire)
            # 10GbE: 67.2ns for 64-byte frame
            serial_delay = (link.frame_size_bytes * 8) / link.bandwidth_gbps
            breakdown.serialization_ns += serial_delay
            
            # Switch/router delay
            if link.device_type == 'cut_through_switch':
                # Cut-through: forward after seeing destination MAC (~300ns)
                breakdown.switching_ns += 300
            elif link.device_type == 'store_forward_switch':
                # Store-and-forward: wait for full frame (~5000ns for 64B)
                breakdown.switching_ns += 5000
            
            # NIC delay (if applicable)
            if i == 0:  # Source NIC
                breakdown.nic_tx_ns += link.nic_tx_latency_ns
            if i == len(path) - 2:  # Destination NIC
                breakdown.nic_rx_ns += link.nic_rx_latency_ns
        
        return breakdown
    
    def compare_microwave_vs_fiber(self, 
                                    point_a: Location, 
                                    point_b: Location) -> dict:
        """
        Microwave travels at ~c (speed of light in vacuum).
        Fiber travels at ~0.67c (speed of light in glass).
        For long distances, microwave wins despite being line-of-sight.
        """
        distance_km = self.calculate_distance(point_a, point_b)
        
        # Speed of light
        c = 299792.458  # km/s
        
        # Fiber: ~0.67c due to refractive index, plus routing overhead
        fiber_speed = c * 0.67
        fiber_distance = distance_km * 1.3  # Routing adds ~30%
        fiber_latency_ms = (fiber_distance / fiber_speed) * 1000
        
        # Microwave: ~0.99c, nearly straight line
        microwave_speed = c * 0.99
        microwave_distance = distance_km * 1.02  # Slight deviation for terrain
        microwave_latency_ms = (microwave_distance / microwave_speed) * 1000
        
        return {
            'fiber_latency_ms': fiber_latency_ms,
            'microwave_latency_ms': microwave_latency_ms,
            'savings_ms': fiber_latency_ms - microwave_latency_ms,
            'savings_percent': (fiber_latency_ms - microwave_latency_ms) / fiber_latency_ms * 100
        }
智能 NIC 处理
// Smart NIC (Bluefield/Netronome) for in-NIC processing
// Process market data before it hits CPU

class SmartNICProcessor {
public:
    // Run on NIC's ARM cores / P4 engine
    struct PacketContext {
        uint64_t timestamp_hw;    // Hardware timestamp from PHY
        uint8_t* packet_data;
        uint16_t length;
    };
    
    // This runs on the NIC, not the host CPU
    __attribute__((section(".nic_code")))
    Action process_packet(PacketContext* ctx) {
        // Parse at line rate
        auto* eth = reinterpret_cast<EthernetHeader*>(ctx->packet_data);
        
        if (eth->ethertype != ETHERTYPE_IP) {
            return Action::PASS_TO_HOST;
        }
        
        auto* ip = reinterpret_cast<IPHeader*>(eth + 1);
        auto* udp = reinterpret_cast<UDPHeader*>(ip + 1);
        
        // Filter: only process market data multicast
        if (!is_market_data_multicast(ip->dst_addr, udp->dst_port)) {
            return Action::PASS_TO_HOST;
        }
        
        auto* msg = reinterpret_cast<MarketDataMessage*>(udp + 1);
        
        // Simple filtering: drop if not in our symbol universe
        if (!is_in_universe(msg->symbol_id)) {
            return Action::DROP;
        }
        
        // Add hardware timestamp and pass to host
        ctx->packet_data = prepend_timestamp(ctx->packet_data, ctx->timestamp_hw);
        
        return Action::PASS_TO_HOST;
    }
};
精确时间协议(PTP)
// Hardware-based time synchronization

class PTPTimeSync {
    /*
     * Jump uses PTP (IEEE 1588) for nanosecond-accurate time sync.
     * Critical for correlating events across systems and fair latency measurement.
     */
    
public:
    void configure_ptp_hardware(int nic_fd) {
        // Enable hardware timestamping
        struct hwtstamp_config config = {};
        config.tx_type = HWTSTAMP_TX_ON;
        config.rx_filter = HWTSTAMP_FILTER_ALL;
        
        struct ifreq ifr = {};
        ifr.ifr_data = (char*)&config;
        ioctl(nic_fd, SIOCSHWTSTAMP, &ifr);
        
        // Get PHC (PTP Hardware Clock) device
        struct ethtool_ts_info info = {};
        info.cmd = ETHTOOL_GET_TS_INFO;
        ifr.ifr_data = (char*)&info;
        ioctl(nic_fd, SIOCETHTOOL, &ifr);
        
        // Open PHC device
        char phc_device[32];
        snprintf(phc_device, sizeof(phc_device), "/dev/ptp%d", info.phc_index);
        phc_fd_ = open(phc_device, O_RDWR);
    }
    
    uint64_t get_hardware_time_ns() {
        struct ptp_clock_time ptc;
        ioctl(phc_fd_, PTP_CLOCK_GETTIME, &ptc);
        return ptc.sec * 1000000000ULL + ptc.nsec;
    }
    
    // Extract hardware timestamp from received packet
    uint64_t extract_rx_timestamp(struct msghdr* msg) {
        for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg); 
             cmsg; 
             cmsg = CMSG_NXTHDR(msg, cmsg)) {
            
            if (cmsg->cmsg_level == SOL_SOCKET &&
                cmsg->cmsg_type == SCM_TIMESTAMPING) {
                
                struct scm_timestamping* ts = 
                    (struct scm_timestamping*)CMSG_DATA(cmsg);
                
                // Use hardware timestamp (ts[2]) not software (ts[0])
                return ts->ts[2].tv_sec * 1000000000ULL + 
                       ts->ts[2].tv_nsec;
            }
        }
        return 0;
    }

private:
    int phc_fd_;
};
端到端延迟测量
class WireToWireLatency {
    /*
     * Measure true latency: from photons arriving at RX NIC
     * to photons leaving TX NIC.
     * Software timestamps are useless at these scales.
     */
    
public:
    struct Measurement {
        uint64_t rx_hw_timestamp;    // When packet hit our NIC (hardware)
        uint64_t tx_hw_timestamp;    // When response left our NIC (hardware)
        uint64_t wire_to_wire_ns;    // Total latency
        
        // Component breakdown (if instrumented)
        uint64_t parse_ns;
        uint64_t strategy_ns;
        uint64_t order_build_ns;
        uint64_t tx_queue_ns;
    };
    
    void record_tick_to_trade(
        uint64_t market_data_rx_hw_ts,
        uint64_t order_tx_hw_ts) {
        
        uint64_t latency_ns = order_tx_hw_ts - market_data_rx_hw_ts;
        
        histogram_.record(latency_ns);
        
        // Alert if we exceed target
        if (latency_ns > target_latency_ns_) {
            log_slow_path(latency_ns);
        }
    }
    
    void print_histogram() {
        // Typical Jump-style output:
        // p50: 180ns, p99: 320ns, p999: 890ns, max: 1.2us
        auto stats = histogram_.get_stats();
        printf("Wire-to-wire latency:\n");
        printf("  p50:  %luns\n", stats.p50);
        printf("  p99:  %luns\n", stats.p99);
        printf("  p999: %luns\n", stats.p999);
        printf("  max:  %luns\n", stats.max);
    }
};

思维模型

Jump 通过以下问题来实现超低延迟:

  1. 物理极限是什么? 光速 × 距离
  2. 计算在哪里进行? 将计算移至硬件(FPGA/SmartNIC)
  3. 网络路径是什么? 优化每一跳
  4. 抖动有多大? 最坏情况比平均情况更重要
  5. 能否进行流水线处理? 并行处理,而非顺序处理

Jump 的标志性做法

  • 基于 FPGA 的交易逻辑
  • 用于长距离传输的微波网络
  • 智能 NIC 预处理
  • 硬件 PTP 时间同步
  • 直通交换
  • 端到端延迟测量
  • 纳秒级优化
  • 在每个主要交易所共置
  • 全栈软硬件掌控

评论

支持 Markdown