Skip to main content
Glama
execution.py7.3 kB
import yfinance as yf from typing import Dict, Any, Optional, Literal from config import INITIAL_CAPITAL from tools.alpaca_broker import get_broker import logging logger = logging.getLogger(__name__) # Get the Alpaca broker instance try: broker = get_broker() logger.info("Execution module using Alpaca broker") except Exception as e: logger.error(f"Failed to initialize Alpaca broker: {e}") broker = None def get_positions() -> Dict[str, Any]: """ Retrieves the current state of all held positions and cash balance. Returns: Dict with 'cash' and 'positions' keys """ if broker is None: return { "error": "Alpaca broker not initialized. Check your API credentials.", "cash": 0, "positions": {} } try: account = broker.get_account() positions_raw = broker.get_all_positions() # Convert to simple format: {symbol: qty} positions = { symbol: details['qty'] for symbol, details in positions_raw.items() } return { "cash": account['cash'], "equity": account['equity'], "buying_power": account['buying_power'], "positions": positions } except Exception as e: logger.error(f"Failed to get positions: {e}") return { "error": str(e), "cash": 0, "positions": {} } def place_order( symbol: str, side: Literal["buy", "sell"], qty: float, order_type: Literal["market", "limit"] = "market", limit_price: Optional[float] = None ) -> str: """ Submits a market or limit order to Alpaca paper trading. Args: symbol: Ticker symbol. side: 'buy' or 'sell'. qty: Quantity to trade. order_type: 'market' or 'limit'. limit_price: Required if order_type is 'limit'. Returns: Confirmation message or error """ if broker is None: return "ERROR: Alpaca broker not initialized. Check your API credentials in .env file." # Import here to avoid circular dependency from tools.risk_engine import validate_trade try: # Get current price for risk validation ticker = yf.Ticker(symbol) try: current_price = ticker.fast_info.last_price except: return f"Failed to get price for {symbol}" if current_price is None: return f"Failed to get price for {symbol}" # Pre-Trade Risk Check risk_error = validate_trade(symbol, side, qty, current_price) if risk_error: logger.warning(f"Trade rejected by risk engine: {risk_error}") return risk_error # Submit order to Alpaca if order_type == "market": logger.info(f"Submitting MARKET order: {side.upper()} {qty} {symbol}") order_result = broker.submit_market_order(symbol, side, qty) logger.info(f"Order submitted successfully: ID={order_result['order_id']}") return ( f"✅ Market Order Submitted: {side.upper()} {qty} {symbol}\n" f"Order ID: {order_result['order_id']}\n" f"Status: {order_result['status']}\n" f"Submitted at: {order_result['submitted_at']}" ) elif order_type == "limit": if not limit_price: return "ERROR: Limit price required for limit orders." # Validate limit price direction if side == "buy" and limit_price > current_price: logger.warning(f"Buy limit {limit_price} is above market {current_price}") if side == "sell" and limit_price < current_price: logger.warning(f"Sell limit {limit_price} is below market {current_price}") logger.info(f"Submitting LIMIT order: {side.upper()} {qty} {symbol} @ ${limit_price}") order_result = broker.submit_limit_order(symbol, side, qty, limit_price) logger.info(f"Order submitted successfully: ID={order_result['order_id']}") return ( f"✅ Limit Order Submitted: {side.upper()} {qty} {symbol} @ ${limit_price:.2f}\n" f"Order ID: {order_result['order_id']}\n" f"Status: {order_result['status']}\n" f"Submitted at: {order_result['submitted_at']}" ) else: logger.error(f"Unknown order type requested: {order_type}") return f"ERROR: Unknown order type: {order_type}" except Exception as e: logger.error(f"Order failed: {e}", exc_info=True) return f"ERROR: Order failed - {str(e)}" def cancel_order(order_id: str) -> str: """ Cancels a specific open order. Args: order_id: The Alpaca order ID to cancel Returns: Confirmation message """ if broker is None: return "ERROR: Alpaca broker not initialized." try: logger.info(f"Cancelling order: {order_id}") broker.cancel_order(order_id) logger.info(f"Order {order_id} cancelled successfully") return f"✅ Order {order_id} cancelled successfully" except Exception as e: logger.error(f"Cancel order failed: {e}", exc_info=True) return f"ERROR: Failed to cancel order - {str(e)}" def flatten() -> str: """ Immediately closes all open positions. Returns: Summary of closed positions """ if broker is None: return "ERROR: Alpaca broker not initialized." try: result = broker.close_all_positions() if result['closed_count'] == 0: return "No positions to flatten." msg = [f"✅ Flattened {result['closed_count']} positions:"] for pos in result['positions_closed']: msg.append(f" - {pos['symbol']}: {pos['qty']} shares ({pos['status']})") return "\n".join(msg) except Exception as e: logger.error(f"Flatten failed: {e}") return f"ERROR: Failed to flatten positions - {str(e)}" def get_order_history(status: str = "all") -> str: """ Get order history from Alpaca. Args: status: "all", "open", or "closed" Returns: Formatted order history """ if broker is None: return "ERROR: Alpaca broker not initialized." try: orders = broker.get_orders(status) if not orders: return f"No {status} orders found." msg = [f"=== {status.upper()} ORDERS ({len(orders)}) ==="] for order in orders[:10]: # Limit to 10 most recent msg.append( f"{order['symbol']}: {order['side'].upper()} {order['qty']} " f"({order['type']}, {order['status']}) - {order['submitted_at']}" ) if len(orders) > 10: msg.append(f"\n... and {len(orders) - 10} more orders") return "\n".join(msg) except Exception as e: logger.error(f"Get order history failed: {e}") return f"ERROR: Failed to get order history - {str(e)}"

Implementation Reference

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/N-lia/MonteWalk'

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