stock/notebooks/tutorial.ipynb
2026-02-27 03:17:12 +08:00

617 lines
21 KiB
Plaintext

{
"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
}