{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# OpenClaw Trading Tutorial\n", "\n", "This interactive tutorial covers the key features of the OpenClaw trading system.\n", "\n", "## Table of Contents\n", "\n", "1. [Economic Tracking](#economic-tracking)\n", "2. [Agent System](#agent-system)\n", "3. [Decision Fusion](#decision-fusion)\n", "4. [Portfolio Risk Management](#portfolio-risk-management)\n", "5. [Backtesting](#backtesting)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup\n", "\n", "First, let's import the necessary modules and set up the environment." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "sys.path.insert(0, '../src')\n", "\n", "import random\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "from datetime import datetime, timedelta\n", "\n", "# OpenClaw modules\n", "from openclaw.core.economy import TradingEconomicTracker, SurvivalStatus\n", "from openclaw.agents.base import BaseAgent, ActivityType\n", "from openclaw.fusion.decision_fusion import (\n", " DecisionFusion, AgentOpinion, AgentRole, SignalType, FusionConfig\n", ")\n", "from openclaw.portfolio.risk import PortfolioRiskManager\n", "from openclaw.backtest.engine import BacktestEngine\n", "\n", "print(\"✓ OpenClaw modules imported successfully\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Economic Tracking\n", "\n", "The `TradingEconomicTracker` is the core component for managing agent economics. It tracks:\n", "- Initial capital and current balance\n", "- Token costs (API calls, LLM usage)\n", "- Trade costs (fees, PnL)\n", "- Survival status" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create an economic tracker\n", "tracker = TradingEconomicTracker(\n", " agent_id=\"tutorial_agent\",\n", " initial_capital=10000.0\n", ")\n", "\n", "print(f\"Agent ID: {tracker.agent_id}\")\n", "print(f\"Initial Capital: ${tracker.initial_capital:,.2f}\")\n", "print(f\"Current Balance: ${tracker.balance:,.2f}\")\n", "print(f\"Survival Status: {tracker.get_survival_status().value}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Simulate some trading activity\n", "print(\"\\nSimulating trading activity...\\n\")\n", "\n", "# 1. Calculate decision cost (e.g., LLM API call)\n", "decision_cost = tracker.calculate_decision_cost(\n", " tokens_input=1500,\n", " tokens_output=800,\n", " market_data_calls=3\n", ")\n", "print(f\"1. Decision cost: ${decision_cost:.4f}\")\n", "print(f\" Balance: ${tracker.balance:,.2f}\")\n", "\n", "# 2. Simulate a winning trade\n", "trade_result = tracker.calculate_trade_cost(\n", " trade_value=5000.0,\n", " is_win=True,\n", " win_amount=250.0\n", ")\n", "print(f\"\\n2. Trade result:\")\n", "print(f\" Fee: ${trade_result.fee:.4f}\")\n", "print(f\" PnL: ${trade_result.pnl:+.2f}\")\n", "print(f\" Balance: ${tracker.balance:,.2f}\")\n", "\n", "# 3. Simulate a losing trade\n", "trade_result = tracker.calculate_trade_cost(\n", " trade_value=3000.0,\n", " is_win=False,\n", " loss_amount=150.0\n", ")\n", "print(f\"\\n3. Trade result:\")\n", "print(f\" Fee: ${trade_result.fee:.4f}\")\n", "print(f\" PnL: ${trade_result.pnl:+.2f}\")\n", "print(f\" Balance: ${tracker.balance:,.2f}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# View balance history\n", "history = tracker.get_balance_history()\n", "\n", "print(f\"\\nBalance History ({len(history)} entries):\")\n", "print(\"-\" * 60)\n", "for entry in history[:5]:\n", " print(f\"{entry.timestamp}: ${entry.balance:,.2f} ({entry.change:+.4f}) - {entry.reason}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Visualize balance history\n", "if len(history) > 1:\n", " timestamps = [entry.timestamp for entry in history]\n", " balances = [entry.balance for entry in history]\n", " \n", " plt.figure(figsize=(10, 5))\n", " plt.plot(timestamps, balances, marker='o')\n", " plt.axhline(y=tracker.initial_capital, color='r', linestyle='--', label='Initial Capital')\n", " plt.xlabel('Time')\n", " plt.ylabel('Balance ($)')\n", " plt.title('Agent Balance History')\n", " plt.legend()\n", " plt.xticks(rotation=45)\n", " plt.tight_layout()\n", " plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Agent System\n", "\n", "OpenClaw provides a `BaseAgent` class that you can extend to create custom trading agents.\n", "Each agent has:\n", "- Economic tracking\n", "- Skill levels that improve over time\n", "- Win rate tracking\n", "- Event hooks for customization" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import asyncio\n", "from typing import Dict, Any\n", "\n", "class TutorialAgent(BaseAgent):\n", " \"\"\"A simple agent for tutorial demonstration.\"\"\"\n", " \n", " def __init__(self, agent_id: str, initial_capital: float):\n", " super().__init__(\n", " agent_id=agent_id,\n", " initial_capital=initial_capital,\n", " skill_level=0.5\n", " )\n", " \n", " async def decide_activity(self) -> ActivityType:\n", " \"\"\"Decide what activity to perform.\"\"\"\n", " if self.balance < 1000:\n", " return ActivityType.REST\n", " if self.skill_level < 0.6:\n", " return ActivityType.LEARN\n", " return ActivityType.TRADE\n", " \n", " async def analyze(self, symbol: str) -> Dict[str, Any]:\n", " \"\"\"Analyze a trading symbol.\"\"\"\n", " # Simple random analysis for demonstration\n", " confidence = random.uniform(0.5, 0.9) * self.skill_level\n", " signal = random.choice([\"BUY\", \"SELL\", \"HOLD\"])\n", " \n", " return {\n", " \"symbol\": symbol,\n", " \"signal\": signal,\n", " \"confidence\": confidence,\n", " \"skill_level\": self.skill_level\n", " }\n", "\n", "# Create an agent\n", "agent = TutorialAgent(\n", " agent_id=\"tutorial_001\",\n", " initial_capital=5000.0\n", ")\n", "\n", "print(f\"Agent created: {agent}\")\n", "print(f\"\\nInitial Status:\")\n", "for key, value in agent.get_status_dict().items():\n", " print(f\" {key}: {value}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Simulate agent activity\n", "async def simulate_agent():\n", " symbols = [\"AAPL\", \"GOOGL\", \"MSFT\", \"TSLA\"]\n", " \n", " for i in range(5):\n", " print(f\"\\n--- Iteration {i+1} ---\")\n", " \n", " # Decide activity\n", " activity = await agent.decide_activity()\n", " print(f\"Activity: {activity.value}\")\n", " \n", " if activity == ActivityType.TRADE:\n", " symbol = random.choice(symbols)\n", " analysis = await agent.analyze(symbol)\n", " print(f\"Analysis: {analysis['signal']} {symbol} \"\n", " f\"(confidence: {analysis['confidence']:.1%})\")\n", " \n", " # Simulate trade outcome\n", " is_win = random.random() < analysis['confidence']\n", " pnl = 100 if is_win else -50\n", " agent.record_trade(is_win=is_win, pnl=pnl)\n", " \n", " elif activity == ActivityType.LEARN:\n", " print(\"Agent is learning...\")\n", " agent.improve_skill(0.1)\n", " print(f\"New skill level: {agent.skill_level:.1%}\")\n", " \n", " # Check status\n", " print(f\"Balance: ${agent.balance:,.2f}, Win Rate: {agent.win_rate:.1%}\")\n", "\n", "# Run simulation\n", "await simulate_agent()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Decision Fusion\n", "\n", "Decision Fusion combines opinions from multiple agents to reach a consensus.\n", "Each agent provides a signal with confidence, and the fusion engine weights\n", "them by role and confidence." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a fusion engine\n", "fusion = DecisionFusion(\n", " config=FusionConfig(\n", " confidence_threshold=0.3,\n", " consensus_threshold=0.6,\n", " enable_risk_override=True\n", " )\n", ")\n", "\n", "# Simulate collecting opinions from different agents\n", "symbol = \"AAPL\"\n", "fusion.start_fusion(symbol)\n", "\n", "opinions = [\n", " AgentOpinion(\n", " agent_id=\"market_01\",\n", " role=AgentRole.MARKET_ANALYST,\n", " signal=SignalType.BUY,\n", " confidence=0.75,\n", " reasoning=\"Bullish breakout pattern detected\",\n", " factors=[\"Moving Average\", \"Volume\"]\n", " ),\n", " AgentOpinion(\n", " agent_id=\"sentiment_01\",\n", " role=AgentRole.SENTIMENT_ANALYST,\n", " signal=SignalType.BUY,\n", " confidence=0.80,\n", " reasoning=\"Positive news sentiment\",\n", " factors=[\"News Analysis\", \"Social Media\"]\n", " ),\n", " AgentOpinion(\n", " agent_id=\"fundamental_01\",\n", " role=AgentRole.FUNDAMENTAL_ANALYST,\n", " signal=SignalType.STRONG_BUY,\n", " confidence=0.85,\n", " reasoning=\"Earnings beat expectations\",\n", " factors=[\"EPS Growth\", \"Revenue\"]\n", " ),\n", " AgentOpinion(\n", " agent_id=\"bear_01\",\n", " role=AgentRole.BEAR_RESEARCHER,\n", " signal=SignalType.HOLD,\n", " confidence=0.60,\n", " reasoning=\"Valuation concerns at current levels\",\n", " factors=[\"P/E Ratio\", \"Market Cap\"]\n", " ),\n", " AgentOpinion(\n", " agent_id=\"risk_01\",\n", " role=AgentRole.RISK_MANAGER,\n", " signal=SignalType.BUY,\n", " confidence=0.70,\n", " reasoning=\"Risk levels acceptable\",\n", " factors=[\"Volatility\", \"Liquidity\"]\n", " ),\n", "]\n", "\n", "for opinion in opinions:\n", " fusion.add_opinion(opinion)\n", " print(f\"Added: {opinion.agent_id} -> {opinion.signal.name} ({opinion.confidence:.0%})\")\n", "\n", "print(f\"\\nTotal opinions: {len(opinions)}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Execute fusion\n", "result = fusion.fuse(portfolio_value=100000.0)\n", "\n", "print(f\"\\n{'='*50}\")\n", "print(\"FUSION RESULT\")\n", "print(f\"{'='*50}\")\n", "print(f\"Symbol: {result.symbol}\")\n", "print(f\"Final Signal: {result.final_signal.name}\")\n", "print(f\"Recommendation: {result.get_recommendation_text()}\")\n", "print(f\"Confidence: {result.final_confidence:.1%}\")\n", "print(f\"Consensus: {result.consensus_level:.1%}\")\n", "\n", "print(f\"\\nSupporting Opinions: {len(result.supporting_opinions)}\")\n", "for op in result.supporting_opinions:\n", " print(f\" - {op.agent_id}: {op.signal.name}\")\n", "\n", "print(f\"\\nOpposing Opinions: {len(result.opposing_opinions)}\")\n", "for op in result.opposing_opinions:\n", " print(f\" - {op.agent_id}: {op.signal.name}\")\n", "\n", "if result.execution_plan:\n", " print(f\"\\nExecution Plan:\")\n", " for key, value in result.execution_plan.items():\n", " print(f\" {key}: {value}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. Portfolio Risk Management\n", "\n", "The Portfolio Risk Manager helps manage risk across your entire portfolio.\n", "It monitors:\n", "- Position concentration\n", "- Sector exposure\n", "- Drawdown limits\n", "- Correlation risk" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a portfolio risk manager\n", "risk_manager = PortfolioRiskManager(\n", " max_position_size=0.20, # Max 20% in single position\n", " max_sector_exposure=0.40, # Max 40% in single sector\n", " max_portfolio_var=0.02, # Max 2% daily VaR\n", " max_drawdown=0.15, # Max 15% drawdown\n", " correlation_threshold=0.80 # Flag correlated positions\n", ")\n", "\n", "print(\"Portfolio Risk Manager created\")\n", "print(f\" Max Position Size: {risk_manager.max_position_size:.0%}\")\n", "print(f\" Max Sector Exposure: {risk_manager.max_sector_exposure:.0%}\")\n", "print(f\" Max Drawdown: {risk_manager.max_drawdown:.0%}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Simulate portfolio positions\n", "portfolio = {\n", " \"AAPL\": {\"shares\": 100, \"price\": 175.0, \"sector\": \"Technology\"},\n", " \"MSFT\": {\"shares\": 75, \"price\": 380.0, \"sector\": \"Technology\"},\n", " \"NVDA\": {\"shares\": 50, \"price\": 875.0, \"sector\": \"Technology\"},\n", " \"JPM\": {\"shares\": 150, \"price\": 195.0, \"sector\": \"Financial\"},\n", " \"JNJ\": {\"shares\": 80, \"price\": 145.0, \"sector\": \"Healthcare\"},\n", "}\n", "\n", "# Calculate portfolio value\n", "portfolio_value = sum(pos[\"shares\"] * pos[\"price\"] for pos in portfolio.values())\n", "\n", "print(f\"\\nPortfolio Value: ${portfolio_value:,.2f}\\n\")\n", "\n", "# Analyze each position\n", "positions = {}\n", "for symbol, pos in portfolio.items():\n", " value = pos[\"shares\"] * pos[\"price\"]\n", " weight = value / portfolio_value\n", " positions[symbol] = value\n", " print(f\"{symbol}: ${value:,.2f} ({weight:.1%}) - {pos['sector']}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Validate a new trade\n", "trade_signal = SignalType.BUY\n", "trade_confidence = 0.75\n", "\n", "validation_result = risk_manager.validate_trade_for_fusion(\n", " symbol=\"NVDA\",\n", " signal=trade_signal,\n", " confidence=trade_confidence,\n", " portfolio_value=portfolio_value,\n", " positions=positions\n", ")\n", "\n", "print(f\"\\nTrade Validation for NVDA:\")\n", "print(f\" Signal: {trade_signal.name}\")\n", "print(f\" Confidence: {trade_confidence:.0%}\")\n", "print(f\" Allowed: {validation_result['is_allowed']}\")\n", "print(f\" Risk Score: {validation_result['risk_score']:.2f}\")\n", "print(f\" Position Size Limit: {validation_result['position_size_limit']:.0%}\")\n", "\n", "if validation_result['alerts']:\n", " print(f\"\\n Alerts:\")\n", " for alert in validation_result['alerts']:\n", " print(f\" - [{alert.level.value}] {alert.alert_type}: {alert.message}\")\n", "\n", "if validation_result['reasoning']:\n", " print(f\"\\n Reasoning: {validation_result['reasoning']}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5. Backtesting\n", "\n", "The Backtest Engine allows you to test strategies on historical data.\n", "Note: This requires historical price data to be available." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a backtest engine\n", "backtest = BacktestEngine(\n", " initial_capital=100000.0,\n", " commission_rate=0.001, # 0.1% commission\n", ")\n", "\n", "print(\"Backtest Engine created\")\n", "print(f\" Initial Capital: ${backtest.initial_capital:,.2f}\")\n", "print(f\" Commission: {backtest.commission_rate:.2%}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Simulate backtest results\n", "# In practice, you would run actual backtests with historical data\n", "\n", "# Generate sample trade history\n", "trades = []\n", "dates = pd.date_range(start='2024-01-01', periods=100, freq='D')\n", "\n", "for i, date in enumerate(dates):\n", " if random.random() < 0.1: # 10% chance of trade per day\n", " is_win = random.random() < 0.55 # 55% win rate\n", " pnl = random.uniform(500, 1500) if is_win else random.uniform(-800, -200)\n", " trades.append({\n", " 'date': date,\n", " 'symbol': random.choice(['AAPL', 'MSFT', 'NVDA']),\n", " 'pnl': pnl,\n", " 'is_win': is_win\n", " })\n", "\n", "trades_df = pd.DataFrame(trades)\n", "\n", "if len(trades_df) > 0:\n", " total_pnl = trades_df['pnl'].sum()\n", " win_rate = trades_df['is_win'].mean()\n", " avg_win = trades_df[trades_df['is_win']]['pnl'].mean() if trades_df['is_win'].any() else 0\n", " avg_loss = trades_df[~trades_df['is_win']]['pnl'].mean() if (~trades_df['is_win']).any() else 0\n", " \n", " print(f\"\\nBacktest Results ({len(trades_df)} trades):\")\n", " print(f\" Total PnL: ${total_pnl:,.2f}\")\n", " print(f\" Win Rate: {win_rate:.1%}\")\n", " print(f\" Avg Win: ${avg_win:,.2f}\")\n", " print(f\" Avg Loss: ${avg_loss:,.2f}\")\n", " \n", " # Calculate cumulative PnL\n", " trades_df['cumulative_pnl'] = trades_df['pnl'].cumsum()\n", " \n", " # Plot\n", " plt.figure(figsize=(12, 5))\n", " \n", " plt.subplot(1, 2, 1)\n", " plt.plot(trades_df['date'], trades_df['cumulative_pnl'])\n", " plt.axhline(y=0, color='r', linestyle='--', alpha=0.5)\n", " plt.xlabel('Date')\n", " plt.ylabel('Cumulative PnL ($)')\n", " plt.title('Backtest Cumulative Returns')\n", " plt.xticks(rotation=45)\n", " \n", " plt.subplot(1, 2, 2)\n", " colors = ['green' if w else 'red' for w in trades_df['is_win']]\n", " plt.bar(range(len(trades_df)), trades_df['pnl'], color=colors, alpha=0.7)\n", " plt.axhline(y=0, color='black', linestyle='-', alpha=0.3)\n", " plt.xlabel('Trade Number')\n", " plt.ylabel('PnL ($)')\n", " plt.title('Individual Trade Results')\n", " \n", " plt.tight_layout()\n", " plt.show()\n", "else:\n", " print(\"No trades generated in simulation\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", "This tutorial covered the key components of OpenClaw:\n", "\n", "1. **Economic Tracking**: Manage agent capital, costs, and survival\n", "2. **Agent System**: Create custom agents with skill progression\n", "3. **Decision Fusion**: Combine multiple agent opinions for consensus\n", "4. **Portfolio Risk**: Monitor and manage portfolio-level risks\n", "5. **Backtesting**: Test strategies on historical data\n", "\n", "For more information, see:\n", "- `/examples/` directory for more examples\n", "- `/docs/` for full API documentation\n", "- `/README.md` for project overview" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.0" } }, "nbformat": 4, "nbformat_minor": 4 }