Claude-skill-registry autonomous-trading
Use this skill when setting up or running autonomous stock trading operations. The system continuously researches stocks, makes trading decisions without human input, executes trades on Alpaca paper trading, and sends Telegram notifications. Based on AI-Trader's autonomous agent pattern.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/autonomous-trading" ~/.claude/skills/majiayu000-claude-skill-registry-autonomous-trading && rm -rf "$T"
manifest:
skills/data/autonomous-trading/SKILL.mdsource content
Autonomous Trading Skill
When to Use
Activate when:
- Setting up autonomous trading operations
- Configuring continuous background trading
- Implementing stock screening and selection
- Setting up scheduled trading jobs
- Creating notification systems for autonomous trades
Architecture: Fully Autonomous System
Based on AI-Trader Pattern (refs/AI-Trader/)
┌─────────────────────────────────────────────────┐ │ CONTINUOUS BACKGROUND LOOP │ │ │ │ Every Market Day: │ │ ├── 9:00 AM: Pre-market screening │ │ ├── 9:30 AM: Market open → Analyze & Trade │ │ ├── 12:00 PM: Mid-day review │ │ ├── 4:00 PM: Market close → Daily summary │ │ └── 5:00 PM: Post-market analysis │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ AUTONOMOUS STOCK SELECTION │ │ │ │ 1. Screen Universe (NASDAQ 100) │ │ 2. Filter by Criteria: │ │ - Volume > 1M shares/day │ │ - Price movement > 2% (volatility) │ │ - News events in last 24h │ │ 3. Rank by Opportunity Score │ │ 4. Select Top 5-10 for Deep Analysis │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ MULTI-MODEL ANALYSIS │ │ (Parallel Execution) │ │ │ │ For each selected stock: │ │ ├── Run all 5 AI models │ │ ├── Each model uses TradingAgents framework │ │ ├── Aggregate decisions │ │ └── Consensus → TRADE or PASS │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ AUTOMATIC TRADE EXECUTION │ │ │ │ If consensus reached: │ │ ├── Risk check (position sizing) │ │ ├── Submit order to Alpaca │ │ ├── Log to database │ │ └── Send Telegram notification │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ TELEGRAM NOTIFICATIONS │ │ │ │ Real-time updates to user: │ │ ├── "🔍 Screening 100 stocks..." │ │ ├── "📊 Analyzing NVDA (4/5 models → BUY)" │ │ ├── "✅ Bought 10 shares NVDA @ $850.50" │ │ └── "📈 Daily P&L: +$234.50 (+2.3%)" │ └─────────────────────────────────────────────────┘
Implementation Components
1. Stock Screening & Selection
# src/autonomous/stock_screener.py from typing import List, Dict import yfinance as yf from datetime import datetime, timedelta class AutonomousStockScreener: """ Automatically select stocks for analysis Based on AI-Trader's autonomous decision-making """ # NASDAQ 100 universe (from refs/AI-Trader/agent/base_agent/base_agent.py:44-56) STOCK_UNIVERSE = [ "NVDA", "MSFT", "AAPL", "GOOG", "GOOGL", "AMZN", "META", "AVGO", "TSLA", "NFLX", "PLTR", "COST", "ASML", "AMD", "CSCO", "AZN", "TMUS", "MU", # ... (full list from AI-Trader) ] def __init__(self): self.criteria = { "min_volume": 1_000_000, # Minimum 1M shares/day "min_price_change": 2.0, # At least 2% movement "max_positions": 10, # Max stocks to analyze "lookback_days": 5 # Look back 5 days } async def screen_stocks(self) -> List[Dict]: """ Screen entire universe and select top candidates """ print("🔍 Screening universe of stocks...") candidates = [] for ticker in self.STOCK_UNIVERSE: try: # Get recent data stock = yf.Ticker(ticker) hist = stock.history(period="5d") if len(hist) < 2: continue # Calculate metrics latest_price = hist['Close'].iloc[-1] prev_price = hist['Close'].iloc[-2] price_change_pct = ((latest_price - prev_price) / prev_price) * 100 avg_volume = hist['Volume'].mean() # Apply filters if (avg_volume >= self.criteria["min_volume"] and abs(price_change_pct) >= self.criteria["min_price_change"]): # Check for recent news news = stock.news[:3] if hasattr(stock, 'news') else [] has_news = len(news) > 0 # Calculate opportunity score opportunity_score = ( abs(price_change_pct) * 0.4 + # Price movement (avg_volume / 10_000_000) * 0.3 + # Volume factor (10 if has_news else 0) * 0.3 # News catalyst ) candidates.append({ "ticker": ticker, "price": latest_price, "price_change_pct": price_change_pct, "volume": avg_volume, "has_news": has_news, "opportunity_score": opportunity_score }) except Exception as e: print(f"Error screening {ticker}: {e}") continue # Sort by opportunity score candidates.sort(key=lambda x: x["opportunity_score"], reverse=True) # Select top N selected = candidates[:self.criteria["max_positions"]] print(f"✅ Selected {len(selected)} stocks for analysis:") for s in selected: print(f" • {s['ticker']}: {s['price_change_pct']:+.2f}% | " f"Vol: {s['volume']/1e6:.1f}M | " f"Score: {s['opportunity_score']:.2f}") return selected
2. Autonomous Trading Loop
# src/autonomous/trading_loop.py import asyncio from datetime import datetime, time import pytz from apscheduler.schedulers.asyncio import AsyncIOScheduler class AutonomousTradingLoop: """ Main autonomous trading loop Runs continuously in background """ def __init__(self, telegram_bot, models_orchestrator, alpaca_client): self.bot = telegram_bot self.orchestrator = models_orchestrator self.alpaca = alpaca_client self.screener = AutonomousStockScreener() self.scheduler = AsyncIOScheduler(timezone=pytz.timezone('US/Eastern')) def start(self): """ Schedule autonomous trading jobs """ # Pre-market screening (9:00 AM ET) self.scheduler.add_job( self.pre_market_screening, 'cron', day_of_week='mon-fri', hour=9, minute=0 ) # Market open analysis & trading (9:30 AM ET) self.scheduler.add_job( self.market_open_trading, 'cron', day_of_week='mon-fri', hour=9, minute=30 ) # Mid-day check (12:00 PM ET) self.scheduler.add_job( self.mid_day_review, 'cron', day_of_week='mon-fri', hour=12, minute=0 ) # Market close analysis (4:00 PM ET) self.scheduler.add_job( self.market_close_summary, 'cron', day_of_week='mon-fri', hour=16, minute=0 ) # Start scheduler self.scheduler.start() print("🤖 Autonomous trading loop started!") async def pre_market_screening(self): """ 9:00 AM: Screen stocks for today's trading """ await self.bot.send_notification( "🌅 *Pre-Market Screening Started*\n" "Analyzing NASDAQ 100 stocks..." ) # Screen stocks selected_stocks = await self.screener.screen_stocks() # Send results message = "📋 *Today's Watchlist*\n\n" for stock in selected_stocks: message += ( f"• *{stock['ticker']}* " f"({stock['price_change_pct']:+.2f}%)\n" f" Score: {stock['opportunity_score']:.2f}\n" ) await self.bot.send_notification(message) # Store for market open self.daily_watchlist = selected_stocks async def market_open_trading(self): """ 9:30 AM: Analyze watchlist and execute trades """ await self.bot.send_notification( "🔔 *Market Open - Starting Analysis*\n" f"Analyzing {len(self.daily_watchlist)} stocks with all models..." ) for stock in self.daily_watchlist: await self.analyze_and_trade(stock) await self.bot.send_notification( "✅ *Market Open Analysis Complete*" ) async def analyze_and_trade(self, stock: Dict): """ Run multi-model analysis and execute trade if consensus """ ticker = stock['ticker'] # Notify start await self.bot.send_notification( f"🤖 Analyzing *{ticker}*..." ) # Run all models in parallel model_results = await self.orchestrator.run_all_models(ticker) # Aggregate decisions aggregated = self.orchestrator.aggregate_decisions(model_results) # Check consensus if aggregated['high_consensus']: # >70% agreement decision = aggregated['majority_decision'] # Send analysis summary message = self._format_analysis_result(ticker, aggregated) await self.bot.send_notification(message) # Execute trade if BUY/SELL (not HOLD) if decision in ['BUY', 'SELL']: await self._execute_autonomous_trade( ticker, decision, aggregated ) else: # Low consensus - skip trade await self.bot.send_notification( f"⏭️ Skipping *{ticker}* - Low consensus " f"({aggregated['consensus_level']:.0%})" ) async def _execute_autonomous_trade( self, ticker: str, action: str, analysis: Dict ): """ Automatically execute trade on Alpaca paper trading """ # Calculate position size (risk-based) portfolio = self.alpaca.get_account() portfolio_value = float(portfolio.portfolio_value) # Risk 2-5% per position based on consensus strength risk_pct = 0.02 + (analysis['consensus_level'] - 0.7) * 0.1 position_value = portfolio_value * risk_pct # Get current price current_price = self.alpaca.get_latest_trade(ticker).price shares = int(position_value / current_price) if shares < 1: await self.bot.send_notification( f"⚠️ Position size too small for {ticker} - skipping" ) return try: # Submit order to Alpaca if action == 'BUY': order = self.alpaca.submit_order( symbol=ticker, qty=shares, side='buy', type='market', time_in_force='day' ) else: # SELL # Check if we have position to sell positions = self.alpaca.list_positions() position = next((p for p in positions if p.symbol == ticker), None) if not position: await self.bot.send_notification( f"⚠️ No position in {ticker} to sell" ) return order = self.alpaca.submit_order( symbol=ticker, qty=shares, side='sell', type='market', time_in_force='day' ) # Success notification await self.bot.send_notification( f"✅ *Trade Executed*\n\n" f"Action: {action}\n" f"Stock: {ticker}\n" f"Shares: {shares}\n" f"Price: ${current_price:.2f}\n" f"Value: ${shares * current_price:.2f}\n" f"Consensus: {analysis['consensus_level']:.0%}\n\n" f"Order ID: {order.id}" ) # Log to database await self._log_trade(ticker, action, shares, current_price, analysis) except Exception as e: await self.bot.send_notification( f"❌ *Trade Failed*\n" f"Stock: {ticker}\n" f"Error: {str(e)}" ) async def mid_day_review(self): """ 12:00 PM: Check positions and send update """ positions = self.alpaca.list_positions() account = self.alpaca.get_account() message = "🕛 *Mid-Day Portfolio Update*\n\n" message += f"Portfolio Value: ${float(account.portfolio_value):.2f}\n" message += f"P&L Today: ${float(account.equity) - float(account.last_equity):.2f}\n\n" if positions: message += "*Current Positions:*\n" for pos in positions: unrealized_pl = float(pos.unrealized_pl) emoji = "📈" if unrealized_pl > 0 else "📉" message += ( f"{emoji} {pos.symbol}: {pos.qty} shares " f"({unrealized_pl:+.2f})\n" ) else: message += "No open positions" await self.bot.send_notification(message) async def market_close_summary(self): """ 4:00 PM: Daily summary and performance report """ account = self.alpaca.get_account() positions = self.alpaca.list_positions() # Calculate daily P&L portfolio_value = float(account.portfolio_value) daily_pl = float(account.equity) - float(account.last_equity) daily_pl_pct = (daily_pl / float(account.last_equity)) * 100 # Get model leaderboard leaderboard = await self.orchestrator.get_leaderboard() message = "🏁 *Market Close Summary*\n\n" message += f"*Portfolio Performance*\n" message += f"Value: ${portfolio_value:.2f}\n" message += f"Daily P&L: ${daily_pl:+.2f} ({daily_pl_pct:+.2f}%)\n\n" # Today's trades today_trades = await self._get_today_trades() message += f"*Today's Trades: {len(today_trades)}*\n" for trade in today_trades: message += f"• {trade['action']} {trade['ticker']}: {trade['shares']} @ ${trade['price']:.2f}\n" message += f"\n*Open Positions: {len(positions)}*\n" for pos in positions: unrealized_pl = float(pos.unrealized_pl) emoji = "📈" if unrealized_pl > 0 else "📉" message += f"{emoji} {pos.symbol}: ${unrealized_pl:+.2f}\n" # Model leaderboard message += f"\n*Model Leaderboard*\n" for i, model in enumerate(leaderboard[:3], 1): medal = {1: "🥇", 2: "🥈", 3: "🥉"}[i] message += f"{medal} {model['model']}: {model['total_return_pct']:+.2f}%\n" await self.bot.send_notification(message) def _format_analysis_result(self, ticker: str, aggregated: Dict) -> str: """Format analysis for Telegram""" decision_emoji = { "BUY": "📈", "SELL": "📉", "HOLD": "⏸️" } message = f"📊 *Analysis: {ticker}*\n\n" message += f"{decision_emoji[aggregated['majority_decision']]} " message += f"*Consensus: {aggregated['majority_decision']}*\n" message += f"Agreement: {aggregated['consensus_level']:.0%}\n" message += f"Confidence: {aggregated['average_confidence']:.0%}\n\n" message += "*Model Votes:*\n" for result in aggregated['individual_decisions']: emoji = decision_emoji[result['decision']] message += f"{emoji} {result['model']}: {result['decision']}\n" return message
3. Telegram Notification System
# src/autonomous/telegram_notifier.py from telegram import Bot from telegram.constants import ParseMode import os class TelegramNotifier: """ Send real-time notifications to user """ def __init__(self): self.bot = Bot(token=os.getenv('TELEGRAM_BOT_TOKEN')) self.chat_id = os.getenv('TELEGRAM_CHAT_ID') async def send_notification(self, message: str): """Send formatted message to user""" try: await self.bot.send_message( chat_id=self.chat_id, text=message, parse_mode=ParseMode.MARKDOWN ) except Exception as e: print(f"Failed to send Telegram notification: {e}") async def send_chart(self, ticker: str, chart_path: str): """Send chart image""" try: with open(chart_path, 'rb') as photo: await self.bot.send_photo( chat_id=self.chat_id, photo=photo, caption=f"📊 Chart for {ticker}" ) except Exception as e: print(f"Failed to send chart: {e}") async def send_daily_digest(self, digest: Dict): """Send comprehensive daily digest""" message = "📧 *Daily Trading Digest*\n\n" # Summary stats message += "*Portfolio*\n" message += f"Value: ${digest['portfolio_value']:.2f}\n" message += f"Daily P&L: ${digest['daily_pl']:+.2f} ({digest['daily_pl_pct']:+.2f}%)\n" message += f"Total Return: {digest['total_return_pct']:+.2f}%\n\n" # Trades executed message += f"*Trades: {digest['num_trades']}*\n" for trade in digest['trades']: message += f"• {trade['action']} {trade['ticker']}: {trade['shares']} @ ${trade['price']:.2f}\n" # Model performance message += "\n*Model Performance*\n" for model in digest['model_rankings']: message += f"{model['rank']}. {model['model']}: {model['return_pct']:+.2f}%\n" await self.send_notification(message)
4. Main Autonomous Entry Point
# src/autonomous/main.py import asyncio from trading_loop import AutonomousTradingLoop from telegram_notifier import TelegramNotifier from src.orchestrator.model_manager import ModelOrchestrator from alpaca.trading.client import TradingClient import os async def main(): """ Start autonomous trading system """ print("🚀 Starting Autonomous Trading System...") # Initialize components telegram = TelegramNotifier() orchestrator = ModelOrchestrator() # Alpaca paper trading alpaca = TradingClient( api_key=os.getenv('ALPACA_API_KEY'), secret_key=os.getenv('ALPACA_SECRET_KEY'), paper=True # PAPER TRADING ONLY ) # Create trading loop trading_loop = AutonomousTradingLoop( telegram_bot=telegram, models_orchestrator=orchestrator, alpaca_client=alpaca ) # Send startup notification await telegram.send_notification( "🤖 *Autonomous Trading System Online*\n\n" "The system will now:\n" "• Screen stocks automatically\n" "• Analyze with all AI models\n" "• Execute trades on consensus\n" "• Send you real-time updates\n\n" "All trading is on Alpaca paper account.\n" "You will be notified of all actions." ) # Start the loop trading_loop.start() # Keep running print("✅ System running. Press Ctrl+C to stop.") try: while True: await asyncio.sleep(60) except KeyboardInterrupt: print("\n🛑 Shutting down...") await telegram.send_notification( "🛑 *Trading System Stopped*\n" "Autonomous trading has been disabled." ) if __name__ == "__main__": asyncio.run(main())
Deployment for 24/7 Operation
Railway Configuration for Background Jobs
# Procfile (for Railway) web: uvicorn src.main:app --host 0.0.0.0 --port $PORT worker: python src/autonomous/main.py
Docker Setup
# Dockerfile FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY src/ ./src/ COPY .claude/ ./.claude/ # For autonomous mode CMD ["python", "src/autonomous/main.py"]
Safety Features
1. Hard Limits (Always Enforced)
SAFETY_LIMITS = { "max_daily_trades": 20, # Max 20 trades per day "max_position_size_pct": 15, # Max 15% portfolio in one stock "max_daily_loss_pct": 5, # Stop if lose >5% in one day "min_cash_reserve_pct": 20, # Keep at least 20% cash "max_stock_price": 1000, # No stocks >$1000 (avoid expensive) "min_volume": 1_000_000, # Only liquid stocks } def check_safety_limits(trade: Dict, portfolio: Dict) -> bool: """ Verify trade doesn't violate safety limits """ # Check all limits... # Return False if any violated pass
2. Emergency Stop
# Telegram command to stop immediately async def stop_command(update, context): """User can stop system at any time""" global TRADING_ENABLED TRADING_ENABLED = False await update.message.reply_text( "🛑 *EMERGENCY STOP ACTIVATED*\n\n" "All autonomous trading has been halted.\n" "No new trades will be executed.\n" "Existing positions remain open.\n\n" "Use /resume to restart." )
Telegram Commands for Monitoring
/status - Current portfolio and positions /today - Today's trading activity /models - Model leaderboard /stop - Emergency stop (halt all trading) /resume - Resume autonomous trading /limits - View current safety limits /watchlist - See today's selected stocks
Testing Autonomous Mode
1. Dry Run (No Real Trades)
DRY_RUN_MODE = True # Set in .env # All trade executions log but don't submit if not DRY_RUN_MODE: order = alpaca.submit_order(...) else: print(f"[DRY RUN] Would execute: {action} {shares} {ticker}")
2. Start Small
# First week: Only 1-2 stocks, small positions AUTONOMOUS_CONFIG = { "max_stocks_per_day": 2, "position_size_pct": 0.02, # Only 2% per position "require_high_consensus": True # >80% agreement }
Code References
- AI-Trader BaseAgent:
refs/AI-Trader/agent/base_agent/base_agent.py - AI-Trader Stock Universe: Lines 44-56 in base_agent.py
- TradingAgents Graph:
refs/TradingAgents/tradingagents/graph/trading_graph.py - Scheduling: Use APScheduler (similar to AI-Trader patterns)
Best Practices
- Start with dry run - Test without real trades first
- Monitor closely first week - Watch Telegram notifications
- Use paper trading - NEVER use real money initially
- Small positions - Start with 2-5% risk per trade
- High consensus required - Only trade when >70% models agree
- Keep cash reserve - Always maintain 20%+ cash
- Daily limits - Cap number of trades per day
- Emergency stop - Always available via Telegram
Expected Telegram Notifications
Morning (9:00 AM)
🌅 Pre-Market Screening Started Analyzing NASDAQ 100 stocks... 📋 Today's Watchlist • NVDA (+3.2%) Score: 45.6 • AAPL (-2.1%) Score: 42.3
Market Open (9:30 AM)
🔔 Market Open - Starting Analysis Analyzing 5 stocks with all models... 🤖 Analyzing NVDA... 📊 Analysis: NVDA 📈 Consensus: BUY Agreement: 80% Confidence: 75% Model Votes: 📈 Claude: BUY 📈 GPT-5: BUY 📈 Gemini: BUY 📈 DeepSeek: BUY ⏸️ Qwen: HOLD ✅ Trade Executed Action: BUY Stock: NVDA Shares: 10 Price: $850.50 Value: $8,505.00 Consensus: 80%
Throughout Day
⏭️ Skipping AAPL - Low consensus (60%) 🕛 Mid-Day Portfolio Update Portfolio Value: $10,234.50 P&L Today: +$234.50 Current Positions: 📈 NVDA: 10 shares (+150.00)
Market Close (4:00 PM)
🏁 Market Close Summary Portfolio Performance Value: $10,345.00 Daily P&L: +$345.00 (+3.45%) Today's Trades: 2 • BUY NVDA: 10 @ $850.50 • SELL AAPL: 5 @ $175.20 Open Positions: 3 📈 NVDA: +$175.00 📉 MSFT: -$25.00 📈 GOOGL: +$50.00 Model Leaderboard 🥇 Claude: +4.2% 🥈 GPT-5: +3.8% 🥉 Gemini: +3.1%
Usage Example
Setup (One Time):
# Deploy to Railway railway up # Set environment variables AUTONOMOUS_MODE=true DRY_RUN_MODE=false # Set true for testing TELEGRAM_BOT_TOKEN=your_token TELEGRAM_CHAT_ID=your_chat_id ALPACA_API_KEY=paper_key ALPACA_SECRET_KEY=paper_secret
It Runs Automatically:
- Every trading day, system wakes up at 9:00 AM
- Screens stocks, analyzes, trades
- You get Telegram notifications for everything
- No human input required
You Can Monitor:
Send to Telegram bot: /status → See current state /stop → Halt trading immediately /resume → Resume if stopped