From 6a2ae0ebe3f0fcd0d818d9ebb3479bcb6bb8ecaa Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 1 Apr 2026 14:52:16 +0000 Subject: [PATCH] Add hyperliquid-perps exchange type with tests https://claude.ai/code/session_0134TbBXuFUzF4jD4BX45KHo --- README.md | 9 ++++---- client_test.go | 29 ++++++++++++++++++++++++ processor_test.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++ types.go | 5 +++-- 4 files changed, 93 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0b26763..9bb0e7c 100644 --- a/README.md +++ b/README.md @@ -147,10 +147,11 @@ aperiodic basis \ ## Supported Exchanges -| Exchange | ID | -|-----------------|-------------------| -| Binance Futures | `binance-futures` | -| OKX Perpetuals | `okx-perps` | +| Exchange | ID | +|-----------------------|----------------------| +| Binance Futures | `binance-futures` | +| OKX Perpetuals | `okx-perps` | +| Hyperliquid Perpetuals | `hyperliquid-perps` | ## Intervals diff --git a/client_test.go b/client_test.go index d2355d8..5fa168a 100644 --- a/client_test.go +++ b/client_test.go @@ -140,6 +140,16 @@ func TestCLI_Symbols_InvalidAPIKey(t *testing.T) { } } +func TestCLI_Symbols_HyperliquidPerps_InvalidAPIKey(t *testing.T) { + t.Setenv("APERIODIC_API_URL", DefaultBaseURL) + t.Setenv("APERIODIC_API_KEY", "invalid-key") + + _, stderr, code := runCLI("symbols", "-exchange", "hyperliquid-perps") + if code != 1 { + t.Fatalf("expected exit code 1 for invalid API key, got %d; stderr: %s", code, stderr) + } +} + func TestCLI_OHLCV_InvalidAPIKey(t *testing.T) { t.Setenv("APERIODIC_API_URL", DefaultBaseURL) t.Setenv("APERIODIC_API_KEY", "invalid-key") @@ -159,6 +169,25 @@ func TestCLI_OHLCV_InvalidAPIKey(t *testing.T) { } } +func TestCLI_OHLCV_HyperliquidPerps_InvalidAPIKey(t *testing.T) { + t.Setenv("APERIODIC_API_URL", DefaultBaseURL) + t.Setenv("APERIODIC_API_KEY", "invalid-key") + + outputDir := t.TempDir() + _, stderr, code := runCLI( + "ohlcv", + "-exchange", "hyperliquid-perps", + "-symbol", "perpetual-BTC-USDC:USDC", + "-interval", "1d", + "-start-date", "2025-03-01", + "-end-date", "2025-04-01", + "-output-dir", outputDir, + ) + if code != 1 { + t.Fatalf("expected exit code 1 for invalid API key, got %d; stderr: %s", code, stderr) + } +} + func TestCLI_OHLCV_MissingFlags(t *testing.T) { t.Setenv("APERIODIC_API_KEY", "fake") diff --git a/processor_test.go b/processor_test.go index c26500e..4c20e5f 100644 --- a/processor_test.go +++ b/processor_test.go @@ -7,6 +7,62 @@ import ( "testing" ) +func TestCLI_Symbols_HyperliquidPerps(t *testing.T) { + requireAPIKey(t) + + stdout, stderr, code := runCLI("symbols", "-exchange", "hyperliquid-perps") + if code != 0 { + t.Fatalf("expected exit code 0, got %d; stderr: %s", code, stderr) + } + + lines := strings.Split(strings.TrimSpace(stdout), "\n") + if len(lines) == 0 { + t.Fatal("expected at least one symbol in output") + } +} + +func TestCLI_OHLCV_HyperliquidPerps_Download(t *testing.T) { + requireAPIKey(t) + + outputDir := t.TempDir() + + stdout, stderr, code := runCLI( + "ohlcv", + "-exchange", "hyperliquid-perps", + "-symbol", "perpetual-BTC-USDC:USDC", + "-interval", "1d", + "-start-date", "2025-03-01", + "-end-date", "2025-04-01", + "-output-dir", outputDir, + ) + if code != 0 { + t.Fatalf("expected exit code 0, got %d; stderr: %s", code, stderr) + } + + if !strings.Contains(stdout, "Successfully downloaded") { + t.Errorf("expected success message, got: %s", stdout) + } + + files, err := filepath.Glob(filepath.Join(outputDir, "*.parquet")) + if err != nil { + t.Fatalf("failed to glob output dir: %v", err) + } + if len(files) == 0 { + t.Fatal("expected at least one parquet file in output dir") + } + + for _, f := range files { + info, err := os.Stat(f) + if err != nil { + t.Errorf("failed to stat %s: %v", f, err) + continue + } + if info.Size() == 0 { + t.Errorf("expected non-empty file %s", f) + } + } +} + func TestCLI_VTWAP_InvalidAPIKey(t *testing.T) { t.Setenv("APERIODIC_API_URL", DefaultBaseURL) t.Setenv("APERIODIC_API_KEY", "invalid-key") diff --git a/types.go b/types.go index 77204f4..4ef7a38 100644 --- a/types.go +++ b/types.go @@ -23,8 +23,9 @@ const ( type Exchange string const ( - ExchangeBinanceFutures Exchange = "binance-futures" - ExchangeOkxPerps Exchange = "okx-perps" + ExchangeBinanceFutures Exchange = "binance-futures" + ExchangeOkxPerps Exchange = "okx-perps" + ExchangeHyperliquidPerps Exchange = "hyperliquid-perps" ) type TradeMetric string