Skip to main content
Glama
service.py20.6 kB
import logging from typing import Dict, Optional from pybit.unified_trading import HTTP from config import Config # import pandas as pd # Removed as it was only used for talib # from talib import abstract # Removed as talib is no longer used # Logging configuration logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) logger = logging.getLogger(__name__) class BybitService: """A wrapper class for interacting with the Bybit Unified Trading API. Provides methods to call various Bybit API v5 endpoints for market data, account management, and order execution. Handles initialization of the pybit HTTP client. """ def __init__(self): """ Initialize BybitService """ logger.info(f"Initializing Bybit Service - Testnet: {Config.TESTNET}, API Key: {Config.ACCESS_KEY}") self.client = HTTP( testnet=Config.TESTNET, api_key=Config.ACCESS_KEY, api_secret=Config.SECRET_KEY ) # Market data related methods def get_orderbook(self, category: str, symbol: str, limit: int = 50) -> Dict: """ Get orderbook data Args: category (str): Category (spot, linear, inverse, etc.) symbol (str): Symbol (e.g., BTCUSDT) limit (int): Number of orderbook entries to retrieve Returns: Dict: Orderbook data """ return self.client.get_orderbook( category=category, symbol=symbol, limit=limit ) def get_kline(self, category: str, symbol: str, interval: str, start: Optional[int] = None, end: Optional[int] = None, limit: int = 200) -> Dict: """ Get K-line data Args: category: Category (spot, linear, inverse, etc.) symbol: Symbol (e.g., BTCUSDT) interval: Time interval (1, 3, 5, 15, 30, 60, 120, 240, 360, 720, D, W, M) start: Start time (millisecond timestamp) end: End time (millisecond timestamp) limit: Number of records to retrieve Returns: Dict: K-line data """ try: params = { "category": category, "symbol": symbol, "interval": interval, "limit": limit } if start: params["start"] = start if end: params["end"] = end response = self.client.get_kline(**params) return response except Exception as e: logger.error(f"Failed to get K-line data: {str(e)}") return {"error": str(e)} def get_tickers(self, category: str, symbol: str) -> Dict: """ Get ticker information Args: category (str): Category (spot, linear, inverse, etc.) symbol (str): Symbol (e.g., BTCUSDT) Returns: Dict: Ticker information """ return self.client.get_tickers( category=category, symbol=symbol ) # Account related methods def get_wallet_balance(self, accountType: str, coin: Optional[str] = None) -> Dict: """ Get wallet balance Args: accountType (str): Account type (UNIFIED, CONTRACT, SPOT) coin (Optional[str]): Coin symbol Returns: Dict: Wallet balance information """ return self.client.get_wallet_balance( accountType=accountType, coin=coin ) def get_positions(self, category: str, symbol: Optional[str] = None) -> Dict: """ Get position information Args: category (str): Category (spot, linear, inverse, etc.) symbol (Optional[str]): Symbol (e.g., BTCUSDT) Returns: Dict: Position information """ return self.client.get_positions( category=category, symbol=symbol ) # Order related methods def place_order(self, category: str, symbol: str, side: str, orderType: str, qty: str, price: Optional[str] = None, timeInForce: Optional[str] = None, orderLinkId: Optional[str] = None, isLeverage: Optional[int] = None, orderFilter: Optional[str] = None, triggerPrice: Optional[str] = None, triggerBy: Optional[str] = None, orderIv: Optional[str] = None, positionIdx: Optional[int] = None, takeProfit: Optional[str] = None, stopLoss: Optional[str] = None, tpTriggerBy: Optional[str] = None, slTriggerBy: Optional[str] = None, tpLimitPrice: Optional[str] = None, slLimitPrice: Optional[str] = None, tpOrderType: Optional[str] = None, slOrderType: Optional[str] = None) -> Dict: """ Execute order Args: category (str): Category - spot: Spot trading * Minimum order quantity: 0.000011 BTC (up to 6 decimal places) * Minimum order amount: 5 USDT * If buying at market price, qty should be input in USDT units (e.g., "10" = 10 USDT) * If selling at market price, qty should be input in BTC units (e.g., "0.000100" = 0.0001 BTC) * If placing a limit order, qty should be input in BTC units * positionIdx is not used - linear: Futures trading (USDT margin) * positionIdx is required (1: Long, 2: Short) - inverse: Futures trading (coin margin) * positionIdx is required (1: Long, 2: Short) symbol (str): Symbol (e.g., BTCUSDT) side (str): Order direction (Buy, Sell) orderType (str): Order type (Market, Limit) qty (str): Order quantity - Market Buy: qty should be input in USDT units (e.g., "10" = 10 USDT) - Market Sell: qty should be input in BTC units (e.g., "0.000100" = 0.0001 BTC, up to 6 decimal places) - Limit: qty should be input in BTC units (e.g., "0.000100" = 0.0001 BTC, up to 6 decimal places) price (Optional[str]): Order price (for limit order) timeInForce (Optional[str]): Order validity period - GTC: Good Till Cancel (default, for limit order) - IOC: Immediate or Cancel (market order) - FOK: Fill or Kill - PostOnly: Post Only orderLinkId (Optional[str]): Order link ID (unique value) isLeverage (Optional[int]): Use leverage (0: No use, 1: Use) orderFilter (Optional[str]): Order filter - Order: General order (default) - tpslOrder: TP/SL order - StopOrder: Stop order triggerPrice (Optional[str]): Trigger price triggerBy (Optional[str]): Trigger basis orderIv (Optional[str]): Order volatility positionIdx (Optional[int]): Position index - Required for futures (linear/inverse) trading - 1: Long position - 2: Short position - positionIdx is not used for spot trading takeProfit (Optional[str]): Take profit price stopLoss (Optional[str]): Stop loss price tpTriggerBy (Optional[str]): Take profit trigger basis slTriggerBy (Optional[str]): Stop loss trigger basis tpLimitPrice (Optional[str]): Take profit limit price slLimitPrice (Optional[str]): Stop loss limit price tpOrderType (Optional[str]): Take profit order type (Market, Limit) slOrderType (Optional[str]): Stop loss order type (Market, Limit) Returns: Dict: Order result Example: # Spot trading (SPOT account balance required) place_order("spot", "BTCUSDT", "Buy", "Market", "10") # Buy market price for 10 USDT place_order("spot", "BTCUSDT", "Sell", "Market", "0.000100") # Sell market price for 0.0001 BTC place_order("spot", "BTCUSDT", "Buy", "Limit", "0.000100", price="50000") # Buy limit order for 0.0001 BTC # Spot trading - limit order + TP/SL place_order("spot", "BTCUSDT", "Buy", "Limit", "0.000100", price="50000", takeProfit="55000", stopLoss="45000", # TP/SL setting tpOrderType="Market", slOrderType="Market") # Execute TP/SL as market order # Futures trading place_order("linear", "BTCUSDT", "Buy", "Market", "0.001", positionIdx=1) # Buy market price for long position place_order("linear", "BTCUSDT", "Sell", "Market", "0.001", positionIdx=2) # Sell market price for short position Notes: 1. Spot trading order quantity restrictions: - Minimum order quantity: 0.000011 BTC - Minimum order amount: 5 USDT - BTC quantity is only allowed up to 6 decimal places (e.g., 0.000100 O, 0.0001234 X) 2. Pay attention to unit when buying/selling at market price: - Buying: qty should be input in USDT units (e.g., "10" = 10 USDT) - Selling: qty should be input in BTC units (e.g., "0.000100" = 0.0001 BTC) 3. Futures trading requires positionIdx: - Long position: positionIdx=1 - Short position: positionIdx=2 4. positionIdx is not used for spot trading Reference site: https://bybit-exchange.github.io/docs/v5/order/create-order """ try: # Default settings if timeInForce is None: timeInForce = "IOC" if orderType == "Market" else "GTC" if orderFilter is None: orderFilter = "Order" if isLeverage is None: isLeverage = 0 # Check positionIdx for futures trading if category in ["linear", "inverse"]: if not positionIdx or positionIdx not in ["1", "2"]: return {"error": "positionIdx is required for futures trading (1: Long position, 2: Short position)"} # Ignore positionIdx for spot trading if category == "spot": positionIdx = None # Prepare request data request_data = { "category": category, "symbol": symbol, "side": side, "orderType": orderType, "qty": qty, "timeInForce": timeInForce, "orderFilter": orderFilter, "isLeverage": isLeverage } # Add optional parameters if price is not None: request_data["price"] = price if orderLinkId is not None: request_data["orderLinkId"] = orderLinkId if triggerPrice is not None: request_data["triggerPrice"] = triggerPrice if triggerBy is not None: request_data["triggerBy"] = triggerBy if orderIv is not None: request_data["orderIv"] = orderIv if positionIdx is not None: request_data["positionIdx"] = positionIdx if takeProfit is not None: request_data["takeProfit"] = takeProfit if stopLoss is not None: request_data["stopLoss"] = stopLoss if tpTriggerBy is not None: request_data["tpTriggerBy"] = tpTriggerBy if slTriggerBy is not None: request_data["slTriggerBy"] = slTriggerBy if tpLimitPrice is not None: request_data["tpLimitPrice"] = tpLimitPrice if slLimitPrice is not None: request_data["slLimitPrice"] = slLimitPrice if tpOrderType is not None: request_data["tpOrderType"] = tpOrderType if slOrderType is not None: request_data["slOrderType"] = slOrderType # Execute order result = self.client.place_order(**request_data) # Check minimum order quantity/amount if isinstance(result, dict) and "error" in result: if "min_qty" in result and "min_amt" in result: # Minimum order quantity/amount verification failed logger.error(f"Order execution failed: {result['error']}") return { "error": f"{result['error']} (Minimum order quantity: {result['min_qty']} {symbol.replace('USDT', '')}, Minimum order amount: {result['min_amt']} USDT)" } else: logger.error(f"Order execution failed: {result['error']}") return {"error": result['error']} elif result.get("retCode") != 0: logger.error(f"Order execution failed: {result.get('retMsg')}") return {"error": result.get("retMsg")} return result except Exception as e: logger.error(f"Order execution failed: {e}", exc_info=True) return {"error": str(e)} def cancel_order(self, category: str, symbol: str, orderId: Optional[str] = None, orderLinkId: Optional[str] = None, orderFilter: Optional[str] = None) -> Dict: """ Cancel order Args: category (str): Category (spot, linear, inverse, etc.) symbol (str): Symbol (e.g., BTCUSDT) orderId (Optional[str]): Order ID orderLinkId (Optional[str]): Order link ID orderFilter (Optional[str]): Order filter Returns: Dict: Cancel result """ return self.client.cancel_order( category=category, symbol=symbol, orderId=orderId, orderLinkId=orderLinkId, orderFilter=orderFilter ) def get_order_history(self, category: str, symbol: Optional[str] = None, orderId: Optional[str] = None, orderLinkId: Optional[str] = None, orderFilter: Optional[str] = None, orderStatus: Optional[str] = None, startTime: Optional[int] = None, endTime: Optional[int] = None, limit: int = 50) -> Dict: """ Get order history Args: category (str): Category (spot, linear, inverse, etc.) symbol (Optional[str]): Symbol (e.g., BTCUSDT) orderId (Optional[str]): Order ID orderLinkId (Optional[str]): Order link ID orderFilter (Optional[str]): Order filter orderStatus (Optional[str]): Order status startTime (Optional[int]): Start time in milliseconds endTime (Optional[int]): End time in milliseconds limit (int): Number of orders to retrieve Returns: Dict: Order history """ return self.client.get_order_history( category=category, symbol=symbol, orderId=orderId, orderLinkId=orderLinkId, orderFilter=orderFilter, orderStatus=orderStatus, startTime=startTime, endTime=endTime, limit=limit ) def get_open_orders(self, category: str, symbol: Optional[str] = None, orderId: Optional[str] = None, orderLinkId: Optional[str] = None, orderFilter: Optional[str] = None, limit: int = 50) -> Dict: """ Get open orders Args: category (str): Category (spot, linear, inverse, etc.) symbol (Optional[str]): Symbol (e.g., BTCUSDT) orderId (Optional[str]): Order ID orderLinkId (Optional[str]): Order link ID orderFilter (Optional[str]): Order filter limit (int): Number of orders to retrieve Returns: Dict: Open orders """ return self.client.get_open_orders( category=category, symbol=symbol, orderId=orderId, orderLinkId=orderLinkId, orderFilter=orderFilter, limit=limit ) # Leverage related methods def set_leverage(self, category: str, symbol: str, buyLeverage: str, sellLeverage: str) -> Dict: """ Set leverage Args: category (str): Category (spot, linear, inverse, etc.) symbol (str): Symbol (e.g., BTCUSDT) buyLeverage (str): Buy leverage sellLeverage (str): Sell leverage Returns: Dict: Setting result """ return self.client.set_leverage( category=category, symbol=symbol, buyLeverage=buyLeverage, sellLeverage=sellLeverage ) def set_trading_stop(self, category: str, symbol: str, takeProfit: Optional[str] = None, stopLoss: Optional[str] = None, trailingStop: Optional[str] = None, positionIdx: Optional[int] = None) -> Dict: """ Set trading stop Args: category (str): Category (spot, linear, inverse, etc.) symbol (str): Symbol (e.g., BTCUSDT) takeProfit (Optional[str]): Take profit price stopLoss (Optional[str]): Stop loss price trailingStop (Optional[str]): Trailing stop positionIdx (Optional[int]): Position index Returns: Dict: Setting result """ return self.client.set_trading_stop( category=category, symbol=symbol, takeProfit=takeProfit, stopLoss=stopLoss, trailingStop=trailingStop, positionIdx=positionIdx ) def set_margin_mode(self, category: str, symbol: str, tradeMode: int, buyLeverage: str, sellLeverage: str) -> Dict: """ Set margin mode Args: category (str): Category (spot, linear, inverse, etc.) symbol (str): Symbol (e.g., BTCUSDT) tradeMode (int): Trading mode (0: Isolated, 1: Cross) buyLeverage (str): Buying leverage sellLeverage (str): Selling leverage Returns: Dict: Setting result """ return self.client.set_margin_mode( category=category, symbol=symbol, tradeMode=tradeMode, buyLeverage=buyLeverage, sellLeverage=sellLeverage ) # Utility methods def get_api_key_information(self) -> Dict: """ Get API key information Returns: Dict: API key information """ return self.client.get_api_key_information() def get_instruments_info(self, category: str, symbol: str, status: Optional[str] = None, baseCoin: Optional[str] = None) -> Dict: """ Get exchange information Args: category (str): Category (spot, linear, inverse, etc.) symbol (str): Symbol (e.g., BTCUSDT) status (Optional[str]): Status baseCoin (Optional[str]): Base coin Returns: Dict: Exchange information """ return self.client.get_instruments_info( category=category, symbol=symbol, status=status, baseCoin=baseCoin ) if __name__ == "__main__": # Example usage bybit_service = BybitService() # Example: Get K-line data kline_data = bybit_service.get_kline( category='spot', symbol='BTCUSDT', interval='1', limit=10 ) print("K-line Data:") print(kline_data) # Example: Get Orderbook # orderbook = bybit_service.get_orderbook(category='spot', symbol='BTCUSDT', limit=5) # print("\nOrderbook Data:") # print(orderbook) # Removed get_talib_kline example usage # data = bybit_service.get_talib_kline(...) # print(data)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dlwjdtn535/mcp-bybit-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server