Skip to main content
Glama
trading_client.py8.25 kB
"""Trading client for Opinion.trade using the official SDK.""" import logging from typing import Any, Dict, Optional logger = logging.getLogger(__name__) class TradingAPIError(Exception): """Exception raised for Opinion.trade trading API errors.""" def __init__(self, message: str, error_code: Optional[str] = None): self.message = message self.error_code = error_code super().__init__(self.message) class TradingClient: """Client for Opinion.trade trading operations using opinion_clob_sdk. Wraps the official Opinion.trade SDK for: - Order placement (limit/market) - Order cancellation - Position management - Balance queries - Trade history The SDK handles EIP712 signing automatically. """ def __init__(self, config): """Initialize the trading client with opinion_clob_sdk. Args: config: OpinionConfig with api_key, private_key, chain_id Raises: ImportError: If opinion_clob_sdk is not installed TradingAPIError: If SDK initialization fails """ try: from opinion_clob_sdk import Client as OpinionSDKClient except ImportError: raise ImportError( "opinion-clob-sdk is required for trading mode. " "Install with: pip install opinion-clob-sdk" ) try: self.client = OpinionSDKClient( host=config.api_host, apikey=config.api_key, private_key=config.private_key, chain_id=config.chain_id ) logger.info("Opinion.trade SDK client initialized") except Exception as e: logger.error(f"Failed to initialize SDK client: {e}") raise TradingAPIError(f"SDK initialization failed: {str(e)}", "INIT_ERROR") async def place_order( self, token_id: str, side: str, amount: float, price: Optional[float] = None, order_type: str = "LIMIT" ) -> Dict[str, Any]: """Place a limit or market order. Args: token_id: Token ID to trade side: Order side (BUY/SELL) amount: Order size price: Limit price (required for LIMIT orders) order_type: Order type (LIMIT/MARKET) Returns: Order confirmation with order_id Raises: TradingAPIError: If order placement fails """ try: # Create order object for SDK order = { "token_id": token_id, "side": side.upper(), "amount": str(amount), "type": order_type.upper() } if order_type.upper() == "LIMIT": if price is None: raise ValueError("Price required for LIMIT orders") # Format price with max 2 decimals as string order["price"] = f"{price:.2f}" # SDK handles EIP712 signing automatically result = self.client.place_order(order) logger.info(f"Order placed: {result.get('order_id')}") return result except Exception as e: logger.error(f"Order placement failed: {e}") raise TradingAPIError(f"Failed to place order: {str(e)}", "ORDER_FAILED") async def cancel_order(self, order_id: str) -> Dict[str, Any]: """Cancel a specific order. Args: order_id: Order ID to cancel Returns: Cancellation confirmation Raises: TradingAPIError: If cancellation fails """ try: result = self.client.cancel_order(order_id) logger.info(f"Order cancelled: {order_id}") return result except Exception as e: logger.error(f"Order cancellation failed: {e}") raise TradingAPIError(f"Failed to cancel order: {str(e)}", "CANCEL_FAILED") async def cancel_all_orders(self, market_id: Optional[str] = None) -> Dict[str, Any]: """Cancel all open orders (optionally filtered by market). Args: market_id: Optional market filter Returns: Cancellation summary Raises: TradingAPIError: If cancellation fails """ try: # Get open orders first open_orders = await self.get_open_orders(market_id) orders = open_orders if isinstance(open_orders, list) else open_orders.get("list", []) cancelled = [] for order in orders: try: await self.cancel_order(order.get("order_id")) cancelled.append(order.get("order_id")) except Exception as e: logger.warning(f"Failed to cancel order {order.get('order_id')}: {e}") return { "cancelled_count": len(cancelled), "cancelled_orders": cancelled } except Exception as e: logger.error(f"Failed to cancel all orders: {e}") raise TradingAPIError(f"Failed to cancel all orders: {str(e)}", "CANCEL_ALL_FAILED") async def get_open_orders(self, market_id: Optional[str] = None) -> Dict[str, Any]: """Get user's open orders. Args: market_id: Optional market filter Returns: List of open orders Raises: TradingAPIError: If retrieval fails """ try: params = {} if market_id: params["market_id"] = market_id result = self.client.get_my_orders(**params) return result except Exception as e: logger.error(f"Failed to get open orders: {e}") raise TradingAPIError(f"Failed to get open orders: {str(e)}", "GET_ORDERS_FAILED") async def get_positions(self, market_id: Optional[str] = None) -> Dict[str, Any]: """Get current positions with P&L. Args: market_id: Optional market filter Returns: List of positions Raises: TradingAPIError: If retrieval fails """ try: params = {} if market_id: params["market_id"] = market_id result = self.client.get_my_positions(**params) return result except Exception as e: logger.error(f"Failed to get positions: {e}") raise TradingAPIError(f"Failed to get positions: {str(e)}", "GET_POSITIONS_FAILED") async def get_trade_history( self, market_id: Optional[str] = None, limit: int = 100, start_time: Optional[int] = None, end_time: Optional[int] = None ) -> Dict[str, Any]: """Get executed trades history. Args: market_id: Optional market filter limit: Maximum trades to return start_time: Start timestamp (ms) end_time: End timestamp (ms) Returns: List of trades Raises: TradingAPIError: If retrieval fails """ try: params = {"limit": limit} if market_id: params["market_id"] = market_id if start_time: params["start_time"] = start_time if end_time: params["end_time"] = end_time result = self.client.get_my_trades(**params) return result except Exception as e: logger.error(f"Failed to get trade history: {e}") raise TradingAPIError(f"Failed to get trade history: {str(e)}", "GET_TRADES_FAILED") async def get_balances(self) -> Dict[str, Any]: """Get account balances (available + locked). Returns: Balance information Raises: TradingAPIError: If retrieval fails """ try: result = self.client.get_my_balances() return result except Exception as e: logger.error(f"Failed to get balances: {e}") raise TradingAPIError(f"Failed to get balances: {str(e)}", "GET_BALANCES_FAILED")

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/solenyaresearch0000/opinion-MCP'

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