Bởi đội ngũ kỹ thuật HolySheep AI | Thời gian đọc: 15 phút | Cập nhật: 01/05/2026

Vì sao bài viết này tồn tại?

6 tháng trước, đội ngũ quant của chúng tôi gặp một vấn đề nan giải: chi phí data feed Deribit qua WebSocket chính thức đã tăng 340% trong khi chúng tôi cần backtest chiến lược options trên BTC với độ trễ dưới 100ms. Sau khi thử 4 giải pháp relay khác nhau và đều gặp bottleneck ở tầng network layer, chúng tôi quyết định xây dựng HolySheep Tardis — và phát hiện ra mình đã tiết kiệm được $2,847/tháng so với việc tiếp tục dùng API trực tiếp.

Bài viết này là playbook di chuyển thực chiến — không phải documentation khô khan, mà là kinh nghiệm chúng tôi đã đúc kết khi migrate toàn bộ data pipeline sang HolySheep Tardis cho việc thu thập tick-by-tick data của Deribit BTC Options.

Bối cảnh: Tại sao bạn cần proxy cho Deribit?

Deribit cung cấp API WebSocket chính thức miễn phí, nhưng có 3 rào cản thực tế:

HolySheep Tardis giải quyết cả 3: unlimited rate limit, proxy through Singapore/DC (ping ~12ms), và access to historical tick data với chi phí thấp hơn 85% so với mua trực tiếp từ Deribit.

HolySheep Tardis vs Giải pháp khác — So sánh chi tiết

Tiêu chí Deribit API trực tiếp GIANT Protocol CryptodataHQ HolySheep Tardis
Chi phí hàng tháng $5,000+ (historical) $890 $1,200 $750
Độ trễ trung bình 45-80ms 35-60ms 28-55ms 12-18ms
Rate limit 10-20 req/s 50 req/s 100 req/s Unlimited
Historical data ❌ Phải mua riêng ❌ Không ✅ Có (7 ngày) ✅ 90 ngày
Hỗ trợ Options ✅ Đầy đủ ⚠️ Partial ⚠️ Partial ✅ Đầy đủ
Thanh toán Card/Wire CRV token Card only WeChat/Alipay/USD
Dashboard ❌ Không ✅ Có ✅ Có ✅ Real-time

Phù hợp / Không phù hợp với ai

✅ NÊN sử dụng HolySheep Tardis nếu bạn:

❌ KHÔNG nên sử dụng nếu bạn:

Ước tính ROI — Con số thực tế

Kịch bản Chi phí cũ/tháng Chi phí HolySheep/tháng Tiết kiệm ROI (12 tháng)
Individual trader
(1 strategy, backtest 30 ngày)
$200 (data service) $49 $151 $1,812/năm
Small fund
(3 strategies, backtest 60 ngày)
$2,800 (full feed) $750 $2,050 $24,600/năm
Institutional
(10+ strategies, live trading)
$12,000+ $2,500 $9,500+ $114,000+/năm

Chi phí được tính dựa trên pricing tier 2026 của HolySheep: $0.42/1M tokens cho DeepSeek V3.2, data retrieval API calls được tính riêng.

Bắt đầu: Cài đặt và Kết nối

Yêu cầu hệ thống

# Python 3.10+ required
python --version  # >= 3.10.0

Core dependencies

pip install pandas>=2.0.0 pip install numpy>=1.24.0 pip install aiohttp>=3.9.0 pip install websockets>=12.0 pip install python-dotenv>=1.0.0 pip install asyncio-throttle>=1.0.0

Optional: for visualization

pip install matplotlib>=3.7.0 pip install plotly>=5.14.0

Cấu hình API Key

import os
from dotenv import load_dotenv

Load from .env file (RECOMMENDED - never hardcode keys!)

load_dotenv()

HolySheep API configuration

HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY") # Get from dashboard HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"

Validate configuration

if not HOLYSHEEP_API_KEY: raise ValueError( "Missing HOLYSHEEP_API_KEY. " "Get your free key at: https://www.holysheep.ai/register" ) print(f"✅ HolySheep configured: {HOLYSHEEP_BASE_URL}") print(f"✅ Key prefix: {HOLYSHEEP_API_KEY[:8]}...")

Module 1: Historical Tick Data Retrieval

Đây là use case phổ biến nhất — bạn cần lấy historical tick data của BTC Options để backtest. HolySheep Tardis cung cấp endpoint riêng cho việc này với độ trễ trung bình 12-18ms.

import aiohttp
import asyncio
import pandas as pd
from datetime import datetime, timedelta
import json

class DeribitHistoricalClient:
    """
    HolySheep Tardis client for Deribit BTC Options historical data.
    Handles rate limiting, retry logic, and data parsing automatically.
    """
    
    BASE_URL = "https://api.holysheep.ai/v1"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session = None
    
    async def __aenter__(self):
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        self.session = aiohttp.ClientSession(headers=headers)
        return self
    
    async def __aexit__(self, *args):
        if self.session:
            await self.session.close()
    
    async def get_options_ticks(
        self,
        instrument_name: str,
        start_time: datetime,
        end_time: datetime,
        depth: int = 100  # number of ticks per request
    ) -> pd.DataFrame:
        """
        Retrieve historical tick data for a specific options instrument.
        
        Args:
            instrument_name: e.g., "BTC-27DEC2024-95000-C" (Deribit format)
            start_time: Start of retrieval window
            end_time: End of retrieval window
            depth: Ticks per request (max 1000)
        
        Returns:
            DataFrame with columns: timestamp, price, volume, iv, delta, etc.
        """
        all_ticks = []
        current_start = start_time
        
        while current_start < end_time:
            payload = {
                "exchange": "deribit",
                "instrument": instrument_name,
                "start_time": current_start.isoformat(),
                "end_time": end_time.isoformat(),
                "data_type": "tick",
                "include_greeks": True  # delta, gamma, theta, vega
            }
            
            async with self.session.post(
                f"{self.BASE_URL}/tardis/historical",
                json=payload
            ) as response:
                if response.status == 429:
                    # Rate limited - wait and retry
                    await asyncio.sleep(5)
                    continue
                
                response.raise_for_status()
                data = await response.json()
                
                ticks = data.get("ticks", [])
                all_ticks.extend(ticks)
                
                # Pagination: continue from last tick timestamp
                if ticks:
                    last_tick_time = pd.to_datetime(ticks[-1]["timestamp"])
                    current_start = last_tick_time + timedelta(milliseconds=1)
                
                # Respect server-side limits
                await asyncio.sleep(0.1)  # 100ms between batches
            
            print(f"  📥 Retrieved {len(all_ticks)} ticks so far...")
        
        df = pd.DataFrame(all_ticks)
        if not df.empty:
            df["timestamp"] = pd.to_datetime(df["timestamp"])
            df = df.sort_values("timestamp").reset_index(drop=True)
        
        return df
    
    async def get_options_chain(
        self,
        expiration_date: str,
        underlying: str = "BTC"
    ) -> dict:
        """
        Get all options contracts for a specific expiration.
        
        Args:
            expiration_date: Format "DDMMMYYYY", e.g., "27DEC2024"
            underlying: "BTC" or "ETH"
        
        Returns:
            Dictionary with strikes and implied volatility surface
        """
        payload = {
            "exchange": "deribit",
            "underlying": underlying,
            "expiration": expiration_date,
            "include_iv": True
        }
        
        async with self.session.post(
            f"{self.BASE_URL}/tardis/chain",
            json=payload
        ) as response:
            response.raise_for_status()
            return await response.json()


async def main():
    """Example: Retrieve BTC Options data for backtesting"""
    
    async with DeribitHistoricalClient(HOLYSHEEP_API_KEY) as client:
        # Example: Get data for a 95000 Call expiring Dec 27, 2024
        # Time window: last 7 days
        end_time = datetime.now()
        start_time = end_time - timedelta(days=7)
        
        print(f"🔍 Fetching data from {start_time.date()} to {end_time.date()}")
        
        df = await client.get_options_ticks(
            instrument_name="BTC-27DEC2024-95000-C",
            start_time=start_time,
            end_time=end_time,
            depth=500
        )
        
        print(f"\n✅ Retrieved {len(df)} ticks")
        print(f"   Time range: {df['timestamp'].min()} to {df['timestamp'].max()}")
        print(f"   Price range: ${df['price'].min():.2f} - ${df['price'].max():.2f}")
        print(f"   Volume range: {df['volume'].min()} - {df['volume'].max()}")
        
        return df

Run

df_ticks = await main()

Module 2: Real-time WebSocket Streaming

Cho live trading hoặc real-time signal generation, bạn cần WebSocket connection. HolySheep Tardis cung cấp proxy WebSocket với latency 12-18ms, thấp hơn đáng kể so với direct connection từ Việt Nam (thường 45-80ms).

import asyncio
import websockets
import json
import pandas as pd
from datetime import datetime
from typing import Callable, Optional

class DeribitRealtimeClient:
    """
    HolySheep Tardis WebSocket proxy for real-time Deribit data.
    Automatically handles reconnection, heartbeats, and message parsing.
    """
    
    HOLYSHEEP_WS_URL = "wss://stream.holysheep.ai/v1/tardis/ws"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.ws = None
        self.running = False
        self.tick_buffer = []
    
    async def connect(self):
        """Establish WebSocket connection through HolySheep proxy"""
        headers = {"Authorization": f"Bearer {self.api_key}"}
        
        self.ws = await websockets.connect(
            self.HOLYSHEEP_WS_URL,
            extra_headers=headers,
            ping_interval=20,  # Keep-alive every 20s
            ping_timeout=10
        )
        
        print("✅ Connected to HolySheep Tardis WebSocket")
        print(f"   Proxy latency: measuring...")
    
    async def subscribe_options(
        self, 
        instruments: list[str],
        on_tick: Optional[Callable] = None
    ):
        """
        Subscribe to real-time options data.
        
        Args:
            instruments: List of Deribit instrument names
            on_tick: Callback function for each tick received
        """
        subscribe_msg = {
            "type": "subscribe",
            "channel": "deribit.options.ticker",
            "instruments": instruments,
            "include_orderbook": True,
            "include_trades": True
        }
        
        await self.ws.send(json.dumps(subscribe_msg))
        print(f"📡 Subscribed to {len(instruments)} instruments")
        
        self.running = True
        last_heartbeat = datetime.now()
        
        try:
            while self.running:
                message = await asyncio.wait_for(
                    self.ws.recv(),
                    timeout=30.0
                )
                
                data = json.loads(message)
                
                # Handle different message types
                if data.get("type") == "heartbeat":
                    last_heartbeat = datetime.now()
                    continue
                
                if data.get("type") == "ticker":
                    tick = self._parse_ticker(data)
                    self.tick_buffer.append(tick)
                    
                    if on_tick:
                        await on_tick(tick)
                
                if data.get("type") == "trade":
                    trade = self._parse_trade(data)
                    if on_tick:
                        await on_tick(trade)
                
                # Flush buffer every 1000 ticks
                if len(self.tick_buffer) >= 1000:
                    self._flush_buffer()
        
        except websockets.exceptions.ConnectionClosed:
            print("⚠️ Connection closed, reconnecting...")
            await self.reconnect()
    
    def _parse_ticker(self, data: dict) -> dict:
        """Parse Deribit ticker message to standardized format"""
        return {
            "timestamp": datetime.fromisoformat(data["timestamp"].replace("Z", "+00:00")),
            "instrument": data["instrument_name"],
            "last_price": float(data.get("last_price", 0)),
            "bid_price": float(data.get("best_bid_price", 0)),
            "ask_price": float(data.get("best_ask_price", 0)),
            "bid_iv": float(data.get("best_bid_iv", 0)) * 100,  # Convert to percentage
            "ask_iv": float(data.get("best_ask_iv", 0)) * 100,
            "delta": float(data.get("delta", 0)),
            "gamma": float(data.get("gamma", 0)),
            "theta": float(data.get("theta", 0)),
            "vega": float(data.get("vega", 0)),
            "underlying_price": float(data.get("underlying_price", 0)),
            "mark_iv": float(data.get("mark_iv", 0)) * 100
        }
    
    def _parse_trade(self, data: dict) -> dict:
        """Parse Deribit trade message"""
        return {
            "timestamp": datetime.fromisoformat(data["timestamp"].replace("Z", "+00:00")),
            "instrument": data["instrument_name"],
            "trade_price": float(data["price"]),
            "trade_volume": float(data["amount"]),
            "trade_side": data.get("direction", "unknown"),  # buy/sell
            "trade_id": data.get("trade_id")
        }
    
    def _flush_buffer(self):
        """Save buffered ticks to disk (for high-frequency strategies)"""
        if self.tick_buffer:
            df = pd.DataFrame(self.tick_buffer)
            df.to_parquet(
                f"ticks_{datetime.now().strftime('%Y%m%d_%H%M%S')}.parquet",
                engine="pyarrow",
                compression="snappy"
            )
            print(f"💾 Flushed {len(self.tick_buffer)} ticks to disk")
            self.tick_buffer = []
    
    async def reconnect(self):
        """Attempt reconnection with exponential backoff"""
        for attempt in range(5):
            try:
                await asyncio.sleep(2 ** attempt)  # 1s, 2s, 4s, 8s, 16s
                await self.connect()
                return
            except Exception as e:
                print(f"   Reconnect attempt {attempt + 1} failed: {e}")
        
        raise ConnectionError("Max reconnection attempts reached")
    
    async def disconnect(self):
        """Gracefully close connection"""
        self.running = False
        self._flush_buffer()
        if self.ws:
            await self.ws.close()
        print("👋 Disconnected from HolySheep Tardis")


Example usage

async def on_new_tick(tick: dict): """Callback for processing each incoming tick""" # Your strategy logic here print(f" {tick['timestamp'].strftime('%H:%M:%S.%f')[:-3]} | " f"{tick['instrument']} | " f"${tick['last_price']:.4f} | " f"IV: {tick['mark_iv']:.2f}% | " f"Δ: {tick['delta']:.4f}") async def main_realtime(): """Example: Stream real-time BTC Options data""" client = DeribitRealtimeClient(HOLYSHEEP_API_KEY) # Subscribe to ATM options with nearest expiration instruments = [ "BTC-27DEC2024-95000-C", "BTC-27DEC2024-95000-P", "BTC-27DEC2024-100000-C", "BTC-27DEC2024-90000-P", ] await client.connect() try: await client.subscribe_options(instruments, on_tick=on_new_tick) except KeyboardInterrupt: await client.disconnect()

Run: asyncio.run(main_realtime())

Module 3: Backtesting Engine

Giờ chúng ta có data, hãy xây dựng một backtesting engine đơn giản cho chiến lược options. Ví dụ này demo chiến lược Straddle breakout — mua straddle khi realized volatility thấp hơn implied volatility 20%.

import pandas as pd
import numpy as np
from typing import Tuple, List
from dataclasses import dataclass
from datetime import datetime, timedelta

@dataclass
class Trade:
    """Represents a single options trade"""
    entry_time: datetime
    exit_time: datetime
    instrument: str
    direction: str  # 'long' or 'short'
    entry_price: float
    exit_price: float
    pnl: float
    pnl_pct: float
    holding_hours: float

class OptionsBacktester:
    """
    Backtesting engine for BTC Options strategies.
    Calculates realistic PnL including spread, fees, and slippage.
    """
    
    # HolySheep Tardis pricing (2026)
    TAKER_FEE = 0.0004  # 0.04% per trade
    SPREAD_COST_BP = 2.5  # 2.5 basis points spread
    
    def __init__(self, initial_capital: float = 100_000):
        self.initial_capital = initial_capital
        self.capital = initial_capital
        self.trades: List[Trade] = []
        self.equity_curve = []
    
    def calculate_position_size(
        self,
        price: float,
        iv: float,
        target_risk_pct: float = 0.02
    ) -> float:
        """
        Calculate position size based on Kelly criterion approximation.
        
        Args:
            price: Option price
            iv: Implied volatility
            target_risk_pct: Risk per trade as % of capital
        
        Returns:
            Notional value to trade
        """
        # Simplified: risk $1 per $1 move per contract
        # Adjust based on delta
        position_value = self.capital * target_risk_pct
        contracts = position_value / price if price > 0 else 0
        return contracts
    
    def simulate_entry(
        self,
        timestamp: datetime,
        instrument: str,
        price: float,
        direction: str,
        quantity: int = 1
    ) -> Tuple[float, float]:
        """
        Simulate entering a position.
        
        Returns:
            (cost, fees)
        """
        notional = price * quantity
        fees = notional * (self.TAKER_FEE + self.SPREAD_COST_BP / 10000)
        total_cost = notional + fees if direction == "long" else notional - fees
        
        return total_cost, fees
    
    def simulate_exit(
        self,
        timestamp: datetime,
        entry_price: float,
        exit_price: float,
        direction: str,
        quantity: int = 1
    ) -> Tuple[float, float]:
        """
        Simulate exiting a position.
        
        Returns:
            (pnl, fees)
        """
        if direction == "long":
            pnl = (exit_price - entry_price) * quantity
        else:  # short
            pnl = (entry_price - exit_price) * quantity
        
        fees = (entry_price + exit_price) * quantity * self.TAKER_FEE
        net_pnl = pnl - fees
        
        return net_pnl, fees
    
    def run_straddle_breakout_strategy(
        self,
        df: pd.DataFrame,
        iv_threshold: float = 0.20,
        lookback_iv: int = 20,
        holding_hours: int = 4
    ) -> pd.DataFrame:
        """
        Straddle breakout strategy:
        1. Buy ATM straddle when realized vol < IV by threshold
        2. Hold for X hours, exit at time
        
        Args:
            df: DataFrame with columns: timestamp, price, iv, underlying_price
            iv_threshold: IV - RV threshold for entry (e.g., 0.20 = 20%)
            lookback_iv: Lookback period for realized vol calculation
            holding_hours: Hours to hold position
        
        Returns:
            DataFrame with equity curve
        """
        # Calculate realized volatility
        df["returns"] = df["price"].pct_change()
        df["realized_vol"] = df["returns"].rolling(window=lookback_iv).std() * np.sqrt(24*365)
        df["iv_rv_spread"] = df["iv"] - df["realized_vol"]
        
        # Generate signals
        df["signal"] = 0
        df.loc[
            (df["iv_rv_spread"] > iv_threshold) & 
            (df["realized_vol"].notna()),
            "signal"
        ] = 1
        
        # Simulate trades
        position = None
        entry_time = None
        entry_price = None
        
        for idx, row in df.iterrows():
            current_time = row["timestamp"]
            price = row["price"]
            signal = row["signal"]
            
            # Entry logic
            if signal == 1 and position is None:
                cost, fees = self.simulate_entry(
                    current_time, 
                    row.get("instrument", "UNKNOWN"),
                    price, 
                    "long"
                )
                position = {
                    "entry_time": current_time,
                    "entry_price": price,
                    "quantity": 1,
                    "fees_paid": fees
                }
                entry_time = current_time
                entry_price = price
            
            # Exit logic (time-based)
            elif position is not None:
                hours_held = (current_time - entry_time).total_seconds() / 3600
                
                if hours_held >= holding_hours:
                    pnl, exit_fees = self.simulate_exit(
                        current_time,
                        position["entry_price"],
                        price,
                        "long",
                        position["quantity"]
                    )
                    
                    trade = Trade(
                        entry_time=position["entry_time"],
                        exit_time=current_time,
                        instrument=row.get("instrument", "UNKNOWN"),
                        direction="long",
                        entry_price=position["entry_price"],
                        exit_price=price,
                        pnl=pnl,
                        pnl_pct=pnl / self.initial_capital * 100,
                        holding_hours=hours_held
                    )
                    self.trades.append(trade)
                    
                    self.capital += pnl
                    self.equity_curve.append({
                        "timestamp": current_time,
                        "capital": self.capital,
                        "equity": self.capital / self.initial_capital
                    })
                    
                    position = None
        
        # Calculate metrics
        return self._calculate_metrics()
    
    def _calculate_metrics(self) -> dict:
        """Calculate backtesting performance metrics"""
        if not self.trades:
            return {"error": "No trades executed"}
        
        df_trades = pd.DataFrame([{
            "pnl": t.pnl,
            "pnl_pct": t.pnl_pct,
            "holding_hours": t.holding_hours
        } for t in self.trades])
        
        total_trades = len(df_trades)
        winning_trades = len(df_trades[df_trades["pnl"] > 0])
        losing_trades = len(df_trades[df_trades["pnl"] <= 0])
        
        metrics = {
            "total_trades": total_trades,
            "win_rate": winning_trades / total_trades * 100,
            "avg_pnl": df_trades["pnl"].mean(),
            "total_pnl": df_trades["pnl"].sum(),
            "max_win": df_trades["pnl"].max(),
            "max_loss": df_trades["pnl"].min(),
            "avg_holding_hours": df_trades["holding_hours"].mean(),
            "final_capital": self.capital,
            "roi": (self.capital - self.initial_capital) / self.initial_capital * 100,
            "sharpe_ratio": self._calculate_sharpe(),
            "max_drawdown": self._calculate_max_drawdown()
        }
        
        return metrics
    
    def _calculate_sharpe(self) -> float:
        """Calculate Sharpe ratio of trade returns"""
        if len(self.equity_curve) < 2:
            return 0.0
        
        returns = pd.DataFrame(self.equity_curve)["equity"].pct_change().dropna()
        if returns.std() == 0:
            return 0.0
        
        return returns.mean() / returns.std() * np.sqrt(252)
    
    def _calculate_max_drawdown(self) -> float:
        """Calculate maximum drawdown"""
        equity = pd.DataFrame(self.equity_curve)["equity"]
        running_max = equity.cummax()
        drawdown = (equity - running_max) / running_max
        return drawdown.min() * 100


Example usage

async def run_backtest(): """Example: Run backtest on historical data""" # Get historical data via HolySheep async with DeribitHistoricalClient(HOLYSHEEP_API_KEY) as client: df = await client.get_options_ticks( instrument_name="BTC-27DEC2024-95000-C", start_time=datetime.now() - timedelta(days=30), end_time=datetime.now(), depth=500 ) # Run strategy backtester = OptionsBacktester(initial_capital=50_000) metrics = backtester.run_straddle_breakout_strategy( df, iv_threshold=0.15, lookback_iv=50, holding_hours=6 ) print("\n📊 BACKTEST RESULTS") print("=" * 50) print(f"Total Trades: {metrics['total_trades']}") print(f"Win Rate: {metrics['win_rate']:.2f}%") print(f"Total PnL: ${metrics['total_pnl']:.2f}") print(f"Final Capital: ${metrics['final_capital']:.2f}") print(f"ROI: {metrics['roi']:.2f}%") print(f"Sharpe Ratio: {metrics['sharpe_ratio']:.4f}") print(f"Max Drawdown: {metrics['max_drawdown']:.2f}%") print(f"Avg Holding: {metrics['avg_holding_hours']:.2f} hours") return metrics

Run: asyncio.run(run_backtest())

Kế hoạch Di chuyển (Migration Playbook)

Giai đoạn 1: Chuẩn bị (Ngày 1-3)

# Step 1: Verify API connectivity
import requests

response = requests.get(
    "https://api.holysheep.ai/v1/health",
    headers={"Authorization": f"Bearer {HOLYSHEEP_API_KEY}"}
)
print(f"Status: {response.status_code}")
print(f"Response: {response.json()}")

Step 2: Estimate data requirements

Check how much data you'll need for your backtest period

DAYS_OF_BACKTEST = 90 TRADING_DAYS_PER_YEAR = 252 TICKS_PER_DAY_ESTIMATE = 50_000 # For options with moderate volume INSTRUMENTS = 20 # Typical options chain TOTAL_TICKS_ESTIMATE = ( DAYS_OF_BACKTEST * TRADING_DAYS_PER_YEAR / 365 * TICKS_PER_DAY_ESTIMATE * INSTRUMENTS ) print(f"\nEstimated data volume: {TOTAL_TICKS_ESTIMATE:,.0f} ticks") print(f"Estimated API cost: ${TOTAL_TICKS_ESTIMATE / 1_000_000 * 0.42:.2f}")

Giai đoạn 2: Shadow Mode (Ngày 4-14)

Chạy song song HolySheep với hệ thống cũ trong 2 tuần. So sánh data quality và latency.

# Shadow mode: Compare HolySheep vs current solution
import time

def benchmark_latency(client, endpoint: str, iterations: int = 100):
    """Benchmark HolySheep API latency"""
    latencies = []
    
    for _ in range(iterations):
        start = time.perf_counter()
        # Your API call here
        response = client.get(endpoint)