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. 04NIC 上でデータを処理
  5. 05ワイヤー間レイテンシを測定

活用シーン

  1. 01低レイテンシの市場データ解析を設計
  2. 02取引システムのネットワーク構成を計画
  3. 03NIC または 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)
  • 不要なホップをすべて排除します
  • 正確な測定にはハードウェアタイムスタンプを使用します
決して行わないこと
  • ソフトウェアタイムスタンプを信用します
  • クリティカルパスで汎用スイッチを使用します
  • ネットワークレイテンシが一定だと考えます
  • 物理層(ケーブル、光学機器、スイッチ)を軽視します
  • パイプライン処理できる場合に逐次処理します
  • カットスルーできる場合にメッセージ全体を待ちます
優先すること
  • 固定ロジックには CPU より FPGA を使用します
  • ストア・アンド・フォワードよりカットスルー・スイッチングを使用します
  • 長距離では光ファイバーよりマイクロ波/ミリ波を使用します
  • 共有インフラより専用回線を使用します
  • ソフトウェアよりハードウェアタイムスタンプを使用します
  • 逐次処理より並列処理を使用します

コードパターン

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 時刻同期
  • カットスルー・スイッチング
  • ワイヤー・ツー・ワイヤーのレイテンシ測定
  • ナノ秒レベルの最適化
  • 主要な取引所すべてでのコロケーション
  • ハードウェア/ソフトウェアのフルスタック所有

コメント