Files
LLM_Engineering_OLD/week4/community-contributions/dkisselev-zz/Week4_Excersise_Trading.ipynb
Dmitry Kisselev 7143517502 wk4 excersise
2025-10-20 22:08:47 -07:00

1403 lines
60 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "5cd7107e",
"metadata": {},
"source": [
"# Crypto Trading System with Kraken API\n",
"\n",
"A crypto trading system that fetches data from Kraken, visualizes price charts with Simple Moving Averages (SMA), uses LLM to analyze trading signals, and executes real trades on Kraken's sandbox environment.\n",
"\n",
"## Features\n",
"- **Real-time Data**: Fetch BTC/USD and ETH/USD data from Kraken API\n",
"- **Technical Analysis**: Interactive charts with customizable SMA overlays\n",
"- **AI Trading Advisor**: LLM-powered trading recommendations based on technical indicators\n",
"- **Real Trading**: Execute actual trades on Kraken's sandbox environment\n",
"- **Multi-Model Support**: Choose from GPT-5, Claude Sonnet, or Gemini for analysis\n",
"\n",
"## Setup Requirements\n",
"1. **API Keys**: Configure OpenAI, Anthropic, Google, and Kraken API keys in `.env` file\n",
"2. **Kraken Sandbox**: Get sandbox API credentials from [Kraken Developer Portal](https://www.kraken.com/features/api)\n",
"3. **Sandbox Funding**: Kraken sandbox may require initial funding for testing trades\n",
"\n",
"## Process stes\n",
"1. **Market Data Tab**: Select crypto pair and SMA windows, fetch data\n",
"2. **Trading Analysis Tab**: Get LLM-powered trading recommendations\n",
"3. **Paper Trading Tab**: Execute real trades based on AI recommendations\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "31c1f5f0",
"metadata": {},
"outputs": [],
"source": [
"# Install dependencies\n",
"!uv add ccxt"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5c58efdd",
"metadata": {},
"outputs": [],
"source": [
"# Imports and Setup\n",
"import os\n",
"import time\n",
"import pandas as pd\n",
"import numpy as np\n",
"import plotly.graph_objects as go\n",
"from plotly.subplots import make_subplots\n",
"import ccxt\n",
"from datetime import datetime\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
"import gradio as gr\n",
"import warnings\n",
"warnings.filterwarnings(\"ignore\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "48648e9e",
"metadata": {},
"outputs": [],
"source": [
"# API Key Setup\n",
"load_dotenv(override=True)\n",
"\n",
"# LLM API Keys\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
"\n",
"# Kraken API Keys (for sandbox trading)\n",
"kraken_api_key = os.getenv('KRAKEN_API_KEY')\n",
"kraken_secret = os.getenv('KRAKEN_API_SECRET')\n",
"\n",
"# Initialize API clients\n",
"anthropic_url = \"https://api.anthropic.com/v1/\"\n",
"gemini_url = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
"\n",
"clients = {}\n",
"if openai_api_key:\n",
" clients['openai'] = OpenAI(api_key=openai_api_key)\n",
" print(f\"✅ OpenAI API Key loaded: {openai_api_key[:8]}...\")\n",
"else:\n",
" print(\"❌ OpenAI API Key not set\")\n",
"\n",
"if anthropic_api_key:\n",
" clients['anthropic'] = OpenAI(api_key=anthropic_api_key, base_url=anthropic_url)\n",
" print(f\"✅ Anthropic API Key loaded: {anthropic_api_key[:7]}...\")\n",
"else:\n",
" print(\"❌ Anthropic API Key not set\")\n",
"\n",
"if google_api_key:\n",
" clients['google'] = OpenAI(api_key=google_api_key, base_url=gemini_url)\n",
" print(f\"✅ Google API Key loaded: {google_api_key[:8]}...\")\n",
"else:\n",
" print(\"❌ Google API Key not set\")\n",
"\n",
"if kraken_api_key and kraken_secret:\n",
" print(f\"✅ Kraken API Keys loaded: {kraken_api_key[:8]}...\")\n",
"else:\n",
" print(\"❌ Kraken API Keys not set - paper trading will be disabled\")\n",
"\n",
"# Model configuration\n",
"MODELS = {\n",
" \"GPT-5\": {\"model_id\": \"gpt-5-mini\", \"provider\": \"openai\"},\n",
" \"Claude Sonnet\": {\"model_id\": \"claude-sonnet-4-5-20250929\", \"provider\": \"anthropic\"},\n",
" \"Gemini\": {\"model_id\": \"gemini-2.5-flash-lite\", \"provider\": \"google\"}\n",
"}\n",
"\n",
"CRYPTO_PAIRS = {\n",
" \"BTC/USD\": \"PI_XBTUSD\", # Bitcoin futures symbol\n",
" \"ETH/USD\": \"PI_ETHUSD\" # Ethereum futures symbol\n",
"}\n",
"\n",
"print(\"✅ API setup complete!\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "59cdc0df",
"metadata": {},
"outputs": [],
"source": [
"# Kraken Data Fetcher Module\n",
"class KrakenDataFetcher:\n",
" \"\"\"Handles data fetching from Kraken API and SMA calculations\"\"\"\n",
" \n",
" def __init__(self):\n",
" self.exchange = ccxt.kraken({\n",
" 'enableRateLimit': True,\n",
" 'timeout': 30000\n",
" })\n",
" self.cached_data = {}\n",
" \n",
" def fetch_ohlcv(self, symbol, timeframe='1h', limit=720):\n",
" \"\"\"Fetch OHLCV data from Kraken\"\"\"\n",
" try:\n",
" # Convert symbol to Kraken format\n",
" # kraken_symbol = CRYPTO_PAIRS.get(symbol, symbol)\n",
" kraken_symbol = symbol\n",
" \n",
" # Check cache first\n",
" cache_key = f\"{kraken_symbol}_{timeframe}_{limit}\"\n",
" if cache_key in self.cached_data:\n",
" cache_time, data = self.cached_data[cache_key]\n",
" if time.time() - cache_time < 300: # 5 minute cache\n",
" print(f\"📊 Using cached data for {symbol}\")\n",
" return data\n",
" \n",
" print(f\"🔄 Fetching {symbol} data from Kraken...\")\n",
" ohlcv = self.exchange.fetch_ohlcv(kraken_symbol, timeframe, limit=limit)\n",
" \n",
" # Convert to DataFrame\n",
" df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])\n",
" df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')\n",
" df.set_index('timestamp', inplace=True)\n",
" \n",
" # Cache the data\n",
" self.cached_data[cache_key] = (time.time(), df)\n",
" \n",
" print(f\"✅ Fetched {len(df)} records for {symbol}\")\n",
" return df\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error fetching data for {symbol}: {str(e)}\")\n",
" return pd.DataFrame()\n",
" \n",
" def calculate_sma(self, data, window):\n",
" \"\"\"Calculate Simple Moving Average\"\"\"\n",
" if len(data) < window:\n",
" return pd.Series(index=data.index, dtype=float)\n",
" return data['close'].rolling(window=window).mean()\n",
" \n",
" def detect_crossover(self, sma_short, sma_long):\n",
" \"\"\"Detect SMA crossover signals\"\"\"\n",
" if len(sma_short) < 2 or len(sma_long) < 2:\n",
" return \"No data\"\n",
" \n",
" # Get the last two values\n",
" short_current = sma_short.iloc[-1]\n",
" short_previous = sma_short.iloc[-2]\n",
" long_current = sma_long.iloc[-1]\n",
" long_previous = sma_long.iloc[-2]\n",
" \n",
" # Check for crossover\n",
" if pd.isna(short_current) or pd.isna(long_current) or pd.isna(short_previous) or pd.isna(long_previous):\n",
" return \"Insufficient data\"\n",
" \n",
" # Golden cross: short SMA crosses above long SMA\n",
" if short_previous <= long_previous and short_current > long_current:\n",
" return \"Golden Cross (BUY Signal)\"\n",
" \n",
" # Death cross: short SMA crosses below long SMA\n",
" if short_previous >= long_previous and short_current < long_current:\n",
" return \"Death Cross (SELL Signal)\"\n",
" \n",
" # No crossover\n",
" if short_current > long_current:\n",
" return \"Short SMA above Long SMA\"\n",
" else:\n",
" return \"Short SMA below Long SMA\"\n",
" \n",
" def get_market_summary(self, data, sma_short, sma_long):\n",
" \"\"\"Get market summary for LLM analysis\"\"\"\n",
" if data.empty:\n",
" return {}\n",
" \n",
" current_price = data['close'].iloc[-1]\n",
" price_change = ((current_price - data['close'].iloc[-2]) / data['close'].iloc[-2]) * 100 if len(data) > 1 else 0\n",
" \n",
" # Volume analysis\n",
" avg_volume = data['volume'].rolling(window=10).mean().iloc[-1] if len(data) >= 10 else data['volume'].mean()\n",
" current_volume = data['volume'].iloc[-1]\n",
" volume_ratio = current_volume / avg_volume if avg_volume > 0 else 1\n",
" \n",
" # Price momentum (last 5 periods)\n",
" momentum = ((data['close'].iloc[-1] - data['close'].iloc[-6]) / data['close'].iloc[-6]) * 100 if len(data) >= 6 else 0\n",
" \n",
" return {\n",
" 'current_price': current_price,\n",
" 'price_change_pct': round(price_change, 2),\n",
" 'current_volume': current_volume,\n",
" 'volume_ratio': round(volume_ratio, 2),\n",
" 'momentum_5d': round(momentum, 2),\n",
" 'sma_short': sma_short.iloc[-1] if not sma_short.empty else None,\n",
" 'sma_long': sma_long.iloc[-1] if not sma_long.empty else None,\n",
" 'crossover_status': self.detect_crossover(sma_short, sma_long)\n",
" }\n",
"\n",
"# Initialize data fetcher\n",
"data_fetcher = KrakenDataFetcher()\n",
"print(\"✅ Kraken Data Fetcher initialized!\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f5976c68",
"metadata": {},
"outputs": [],
"source": [
"# Chart Builder Module\n",
"class ChartBuilder:\n",
" \"\"\"Creates interactive charts with candlesticks and SMA overlays\"\"\"\n",
" \n",
" def __init__(self):\n",
" self.colors = {\n",
" 'bullish': '#00ff88',\n",
" 'bearish': '#ff4444',\n",
" 'sma_short': '#2196F3',\n",
" 'sma_long': '#FF9800',\n",
" 'volume': '#9C27B0'\n",
" }\n",
" \n",
" def create_candlestick_chart(self, data, sma_short, sma_long, symbol):\n",
" \"\"\"Create interactive candlestick chart with SMA overlays\"\"\"\n",
" if data.empty:\n",
" return go.Figure()\n",
" \n",
" try:\n",
" # Create a simple figure without subplots first\n",
" fig = go.Figure()\n",
" \n",
" # Add candlestick chart using only the data values\n",
" fig.add_trace(go.Candlestick(\n",
" x=list(range(len(data))), \n",
" open=data['open'].values,\n",
" high=data['high'].values,\n",
" low=data['low'].values,\n",
" close=data['close'].values,\n",
" name='Price',\n",
" increasing_line_color='#00ff00',\n",
" decreasing_line_color='#ff0000'\n",
" ))\n",
" \n",
" # Add SMA lines if available\n",
" if sma_short is not None and not sma_short.empty:\n",
" # Filter out NaN values and align with data\n",
" sma_short_clean = sma_short.dropna()\n",
" if not sma_short_clean.empty:\n",
" sma_x = list(range(len(sma_short_clean)))\n",
" fig.add_trace(go.Scatter(\n",
" x=sma_x,\n",
" y=sma_short_clean.values,\n",
" mode='lines',\n",
" name='SMA Short',\n",
" line=dict(color='#2196F3', width=2)\n",
" ))\n",
" \n",
" if sma_long is not None and not sma_long.empty:\n",
" # Filter out NaN values and align with data\n",
" sma_long_clean = sma_long.dropna()\n",
" if not sma_long_clean.empty:\n",
"\n",
" sma_x = list(range(len(sma_long_clean)))\n",
" fig.add_trace(go.Scatter(\n",
" x=sma_x,\n",
" y=sma_long_clean.values,\n",
" mode='lines',\n",
" name='SMA Long',\n",
" line=dict(color='#FF9800', width=2)\n",
" ))\n",
" \n",
" # Update layout\n",
" fig.update_layout(\n",
" title=f'{symbol} Trading Chart',\n",
" xaxis_title=\"Time Period\",\n",
" yaxis_title=\"Price ($)\",\n",
" height=600,\n",
" showlegend=True,\n",
" template='plotly_white'\n",
" )\n",
" \n",
" return fig\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error in chart creation: {str(e)}\")\n",
" # Return a simple empty figure\n",
" return go.Figure()\n",
" \n",
" def _find_crossover_points(self, sma_short, sma_long, timestamps):\n",
" \"\"\"Find crossover points between SMAs\"\"\"\n",
" if len(sma_short) < 2 or len(sma_long) < 2:\n",
" return []\n",
" \n",
" crossover_points = []\n",
" \n",
" for i in range(1, len(sma_short)):\n",
" if pd.isna(sma_short.iloc[i]) or pd.isna(sma_long.iloc[i]) or \\\n",
" pd.isna(sma_short.iloc[i-1]) or pd.isna(sma_long.iloc[i-1]):\n",
" continue\n",
" \n",
" # Golden cross: short SMA crosses above long SMA\n",
" if sma_short.iloc[i-1] <= sma_long.iloc[i-1] and sma_short.iloc[i] > sma_long.iloc[i]:\n",
" crossover_points.append({\n",
" 'timestamp': timestamps[i],\n",
" 'type': 'Golden Cross'\n",
" })\n",
" \n",
" # Death cross: short SMA crosses below long SMA\n",
" elif sma_short.iloc[i-1] >= sma_long.iloc[i-1] and sma_short.iloc[i] < sma_long.iloc[i]:\n",
" crossover_points.append({\n",
" 'timestamp': timestamps[i],\n",
" 'type': 'Death Cross'\n",
" })\n",
" \n",
" return crossover_points\n",
" \n",
" def create_summary_chart(self, data, symbol):\n",
" \"\"\"Create a simple price summary chart\"\"\"\n",
" if data.empty:\n",
" return go.Figure()\n",
" \n",
" fig = go.Figure()\n",
" \n",
" # Add price line\n",
" fig.add_trace(go.Scatter(\n",
" x=data.index,\n",
" y=data['close'],\n",
" mode='lines',\n",
" name='Price',\n",
" line=dict(color='white', width=2)\n",
" ))\n",
" \n",
" # Add volume as background bars\n",
" fig.add_trace(go.Bar(\n",
" x=data.index,\n",
" y=data['volume'],\n",
" name='Volume',\n",
" opacity=0.3,\n",
" yaxis='y2'\n",
" ))\n",
" \n",
" fig.update_layout(\n",
" title=f'{symbol} Price Summary',\n",
" xaxis_title='Time',\n",
" yaxis_title='Price (USD)',\n",
" yaxis2=dict(title='Volume', overlaying='y', side='right'),\n",
" template='plotly_dark',\n",
" height=400\n",
" )\n",
" \n",
" return fig\n",
"\n",
"# Initialize chart builder\n",
"chart_builder = ChartBuilder()\n",
"print(\"✅ Chart Builder initialized!\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ad44be2f",
"metadata": {},
"outputs": [],
"source": [
"# LLM Trading Advisor Module\n",
"class TradingAdvisor:\n",
" \"\"\"Uses LLM to analyze market data and provide trading recommendations\"\"\"\n",
" \n",
" def __init__(self):\n",
" self.system_prompt = \"\"\"You are an expert cryptocurrency trading advisor with deep knowledge of technical analysis and market dynamics. \n",
"\n",
"Your task is to analyze cryptocurrency market data and provide clear, actionable trading recommendations.\n",
"\n",
"Key factors to consider:\n",
"1. SMA Crossover Signals: Golden Cross (short SMA > long SMA) suggests bullish momentum, Death Cross (short SMA < long SMA) suggests bearish momentum\n",
"2. Price Momentum: Recent price movements and trends\n",
"3. Volume Analysis: Volume spikes often indicate strong moves\n",
"4. Market Context: Overall market conditions and volatility\n",
"\n",
"Provide your analysis in this exact format:\n",
"DECISION: [BUY/SELL/HOLD]\n",
"CONFIDENCE: [1-10 scale]\n",
"REASONING: [2-3 sentence explanation of your decision]\n",
"RISK_LEVEL: [LOW/MEDIUM/HIGH]\n",
"\n",
"Be concise but thorough in your analysis. Focus on the most relevant technical indicators.\"\"\"\n",
"\n",
" def analyze_market(self, market_summary, model_name=\"GPT-5\", temperature=0.3):\n",
" \"\"\"Analyze market data and provide trading recommendation\"\"\"\n",
" try:\n",
" if not market_summary:\n",
" return {\n",
" 'decision': 'HOLD',\n",
" 'confidence': 1,\n",
" 'reasoning': 'Insufficient market data for analysis',\n",
" 'risk_level': 'HIGH'\n",
" }\n",
" \n",
" # Prepare context for LLM\n",
" context = self._prepare_market_context(market_summary)\n",
" \n",
" # Query the selected model\n",
" response = self._query_llm(model_name, context, temperature)\n",
" \n",
" # Parse the response\n",
" recommendation = self._parse_llm_response(response)\n",
" \n",
" return recommendation\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error in trading analysis: {str(e)}\")\n",
" return {\n",
" 'decision': 'HOLD',\n",
" 'confidence': 1,\n",
" 'reasoning': f'Analysis error: {str(e)}',\n",
" 'risk_level': 'HIGH'\n",
" }\n",
" \n",
" def _prepare_market_context(self, market_summary):\n",
" \"\"\"Prepare market context for LLM analysis\"\"\"\n",
" # Handle SMA values safely\n",
" sma_short = market_summary.get('sma_short')\n",
" sma_long = market_summary.get('sma_long')\n",
" \n",
" sma_short_str = f\"${sma_short:.2f}\" if sma_short is not None else \"N/A\"\n",
" sma_long_str = f\"${sma_long:.2f}\" if sma_long is not None else \"N/A\"\n",
" \n",
" context = f\"\"\"\n",
"Current Market Analysis for Trading Decision:\n",
"\n",
"PRICE DATA:\n",
"- Current Price: ${market_summary.get('current_price', 0):.2f}\n",
"- Price Change: {market_summary.get('price_change_pct', 0):.2f}%\n",
"- 5-Day Momentum: {market_summary.get('momentum_5d', 0):.2f}%\n",
"\n",
"TECHNICAL INDICATORS:\n",
"- Short SMA: {sma_short_str}\n",
"- Long SMA: {sma_long_str}\n",
"- Crossover Status: {market_summary.get('crossover_status', 'Unknown')}\n",
"\n",
"VOLUME ANALYSIS:\n",
"- Current Volume: {market_summary.get('current_volume', 0):,.0f}\n",
"- Volume Ratio: {market_summary.get('volume_ratio', 1):.2f}x (vs 10-day average)\n",
"\n",
"Based on this data, provide a trading recommendation following the specified format.\n",
"\"\"\"\n",
" return context\n",
" \n",
" def _query_llm(self, model_name, context, temperature):\n",
" if model_name not in MODELS:\n",
" raise ValueError(f\"Unknown model: {model_name}\")\n",
" \n",
" model_info = MODELS[model_name]\n",
" provider = model_info['provider']\n",
" model_id = model_info['model_id']\n",
" \n",
" if provider not in clients:\n",
" raise ValueError(f\"Client not available for {provider}\")\n",
" \n",
" try:\n",
" response = clients[provider].chat.completions.create(\n",
" model=model_id,\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": self.system_prompt},\n",
" {\"role\": \"user\", \"content\": context}\n",
" ],\n",
" temperature=temperature if model_id != \"gpt-5-mini\" else 1,\n",
" max_completion_tokens=500 \n",
" )\n",
" \n",
" return response.choices[0].message.content\n",
" \n",
" except Exception as e:\n",
" raise Exception(f\"LLM query failed: {str(e)}\")\n",
"\n",
" \n",
" def _parse_llm_response(self, response):\n",
" \"\"\"Parse LLM response into structured format\"\"\"\n",
" try:\n",
" lines = response.strip().split('\\n')\n",
" decision = 'HOLD'\n",
" confidence = 5\n",
" reasoning = 'No clear reasoning provided'\n",
" risk_level = 'MEDIUM'\n",
" \n",
" for line in lines:\n",
" line = line.strip()\n",
" if line.startswith('DECISION:'):\n",
" decision = line.split(':', 1)[1].strip().upper()\n",
" elif line.startswith('CONFIDENCE:'):\n",
" try:\n",
" confidence = int(line.split(':', 1)[1].strip())\n",
" confidence = max(1, min(10, confidence)) # Clamp between 1-10\n",
" except:\n",
" confidence = 5\n",
" elif line.startswith('REASONING:'):\n",
" reasoning = line.split(':', 1)[1].strip()\n",
" elif line.startswith('RISK_LEVEL:'):\n",
" risk_level = line.split(':', 1)[1].strip().upper()\n",
" \n",
" # Validate decision\n",
" if decision not in ['BUY', 'SELL', 'HOLD']:\n",
" decision = 'HOLD'\n",
" \n",
" # Validate risk level\n",
" if risk_level not in ['LOW', 'MEDIUM', 'HIGH']:\n",
" risk_level = 'MEDIUM'\n",
" \n",
" return {\n",
" 'decision': decision,\n",
" 'confidence': confidence,\n",
" 'reasoning': reasoning,\n",
" 'risk_level': risk_level,\n",
" 'raw_response': response\n",
" }\n",
" \n",
" except Exception as e:\n",
" return {\n",
" 'decision': 'HOLD',\n",
" 'confidence': 1,\n",
" 'reasoning': f'Failed to parse LLM response: {str(e)}',\n",
" 'risk_level': 'HIGH',\n",
" 'raw_response': response\n",
" }\n",
" \n",
" def get_confidence_color(self, confidence):\n",
" \"\"\"Get color based on confidence level\"\"\"\n",
" if confidence >= 8:\n",
" return '#00ff88' # Green\n",
" elif confidence >= 6:\n",
" return '#ffaa00' # Orange\n",
" else:\n",
" return '#ff4444' # Red\n",
" \n",
" def get_decision_emoji(self, decision):\n",
" \"\"\"Get emoji for decision\"\"\"\n",
" emojis = {\n",
" 'BUY': '🟢',\n",
" 'SELL': '🔴',\n",
" 'HOLD': '🟡'\n",
" }\n",
" return emojis.get(decision, '❓')\n",
"\n",
"# Initialize trading advisor\n",
"trading_advisor = TradingAdvisor()\n",
"print(\"✅ Trading Advisor initialized!\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae115eb0",
"metadata": {},
"outputs": [],
"source": [
"# Paper Trader Module for Kraken Sandbox\n",
"class PaperTrader:\n",
" \"\"\"Handles real trading on Kraken sandbox environment\"\"\"\n",
" \n",
" def __init__(self):\n",
" self.exchange = None\n",
" self.connected = False\n",
" self.trade_history = []\n",
" \n",
" if kraken_api_key and kraken_secret:\n",
" self._connect_sandbox()\n",
" \n",
" def _connect_sandbox(self):\n",
" \"\"\"Connect to Kraken sandbox environment\"\"\"\n",
" try:\n",
" self.exchange = ccxt.krakenfutures({\n",
" 'apiKey': kraken_api_key, \n",
" 'secret': kraken_secret,\n",
" 'enableRateLimit': True,\n",
" })\n",
"\n",
" self.exchange.set_sandbox_mode(True)\n",
" \n",
" # Test connection\n",
" self.exchange.load_markets()\n",
" self.connected = True\n",
" print(\"✅ Connected to Kraken sandbox environment\")\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Failed to connect to Kraken sandbox: {str(e)}\")\n",
" self.connected = False\n",
" \n",
" def get_balance(self):\n",
" \"\"\"Get real balance from Kraken sandbox\"\"\"\n",
" if not self.connected:\n",
" return {'USD': 0, 'BTC': 0, 'ETH': 0}\n",
" \n",
" try:\n",
" # Fetch real balance from Kraken\n",
" balance = self.exchange.fetch_balance()\n",
" \n",
" # Extract relevant currencies\n",
" kraken_balance = {\n",
" 'USD': balance.get('USD', {}).get('free', 0),\n",
" 'BTC': balance.get('BTC', {}).get('free', 0),\n",
" 'ETH': balance.get('ETH', {}).get('free', 0)\n",
" }\n",
" \n",
" return kraken_balance\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error fetching balance: {str(e)}\")\n",
" return {'USD': 0, 'BTC': 0, 'ETH': 0}\n",
" \n",
" def place_order(self, symbol, side, amount, price=None):\n",
" \"\"\"Place a real trade order on Kraken sandbox\"\"\"\n",
" if not self.connected:\n",
" return {\n",
" 'success': False,\n",
" 'message': \"❌ Not connected to Kraken sandbox\",\n",
" 'trade': None\n",
" }\n",
" \n",
" try:\n",
" # Convert symbol to Kraken format\n",
" kraken_symbol = CRYPTO_PAIRS.get(symbol, symbol)\n",
" \n",
" # Get current market price if not provided\n",
" ticker = self.exchange.fetch_ticker(kraken_symbol)\n",
" \n",
" price = ticker[\"ask\"] if price is None else price\n",
" \n",
" # Check balance before placing order\n",
" balance = self.get_balance()\n",
" crypto_symbol = symbol.split('/')[0]\n",
" \n",
" if side == 'buy':\n",
" required_usd = amount / price\n",
" if balance['USD'] < required_usd:\n",
" return {\n",
" 'success': False,\n",
" 'message': f\"❌ Insufficient USD balance. Required: ${required_usd:.2f}, Available: ${balance['USD']:.2f}\",\n",
" 'trade': None\n",
" }\n",
" else: # sell \n",
" if balance[crypto_symbol] < (amount / price):\n",
" return {\n",
" 'success': False,\n",
" 'message': f\"❌ Insufficient {crypto_symbol} balance. Required: {amount}, Available: {balance[crypto_symbol]}\",\n",
" 'trade': None\n",
" }\n",
" \n",
" # Place market order\n",
"\n",
" order = self.exchange.create_market_order(\n",
" symbol=kraken_symbol,\n",
" side=side,\n",
" amount=amount\n",
" )\n",
" return {\n",
" 'success': True,\n",
" 'message': f\"✅ Placed {side} order for {amount} {kraken_symbol}\",\n",
" 'trade': order\n",
" }\n",
" \n",
" except Exception as e:\n",
" return {\n",
" 'success': False,\n",
" 'message': f\"❌ Order failed: {str(e)}\",\n",
" 'trade': None\n",
" }\n",
"\n",
" def get_positions(self):\n",
" \"\"\"Get current positions from real balance\"\"\"\n",
" try:\n",
" balance = self.get_balance()\n",
" positions = []\n",
" \n",
" for crypto, amount in balance.items():\n",
" if crypto != 'USD' and amount > 0:\n",
" price = self._get_crypto_price(crypto)\n",
" positions.append({\n",
" 'symbol': crypto,\n",
" 'amount': amount,\n",
" 'value_usd': amount * price\n",
" })\n",
" \n",
" return positions\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error getting positions: {str(e)}\")\n",
" return []\n",
" \n",
" def _get_crypto_price(self, crypto):\n",
" \"\"\"Get current price for crypto\"\"\"\n",
" try:\n",
" symbol = f\"{crypto}/USD\"\n",
" ticker = self.exchange.fetch_ticker(CRYPTO_PAIRS.get(symbol, symbol))\n",
" return ticker['last']\n",
" except:\n",
" return 0\n",
" \n",
" def get_trade_history(self, limit=50):\n",
" \"\"\"Get real trade history from Kraken\"\"\"\n",
" if not self.connected:\n",
" return []\n",
" \n",
" try:\n",
" # Fetch recent trades from Kraken\n",
" trades = self.exchange.fetch_my_trades(limit=limit)\n",
" print(\"Obtianed trades\")\n",
" print(trades)\n",
"\n",
" # Format trades for display\n",
" formatted_trades = []\n",
" for trade in trades:\n",
" formatted_trades.append({\n",
" 'timestamp': datetime.fromtimestamp(trade['timestamp'] / 1000),\n",
" 'symbol': trade['symbol'],\n",
" 'side': trade['side'],\n",
" 'amount': trade['cost'],\n",
" 'price': trade['price'],\n",
" 'order_id': trade.get('order', 'unknown'),\n",
" 'status': 'filled'\n",
" })\n",
" \n",
" return formatted_trades\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error fetching trade history: {str(e)}\")\n",
" return self.trade_history[-limit:] if self.trade_history else []\n",
" \n",
" def get_portfolio_value(self):\n",
" \"\"\"Calculate total portfolio value in USD from real balance\"\"\"\n",
" try:\n",
" balance = self.get_balance()\n",
" total_value = balance['USD']\n",
" \n",
" for crypto, amount in balance.items():\n",
" if crypto != 'USD' and amount > 0:\n",
" price = self._get_crypto_price(crypto)\n",
" total_value += amount * price\n",
" \n",
" return total_value\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Error calculating portfolio value: {str(e)}\")\n",
" return 0\n",
" \n",
" def get_order_status(self, order_id):\n",
" \"\"\"Get status of a specific order\"\"\"\n",
" if not self.connected:\n",
" return None\n",
" \n",
" try:\n",
" order = self.exchange.fetch_order(order_id)\n",
" return order\n",
" except Exception as e:\n",
" print(f\"❌ Error fetching order status: {str(e)}\")\n",
" return None\n",
" \n",
" def cancel_order(self, order_id):\n",
" \"\"\"Cancel a pending order\"\"\"\n",
" if not self.connected:\n",
" return False\n",
" \n",
" try:\n",
" result = self.exchange.cancel_order(order_id)\n",
" return result\n",
" except Exception as e:\n",
" print(f\"❌ Error canceling order: {str(e)}\")\n",
" return False\n",
"\n",
"# Initialize paper trader\n",
"paper_trader = PaperTrader()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d586451a",
"metadata": {},
"outputs": [],
"source": [
"# Global state variables\n",
"current_data = pd.DataFrame()\n",
"current_sma_short = pd.Series()\n",
"current_sma_long = pd.Series()\n",
"current_symbol = \"BTC/USD\"\n",
"current_market_summary = {}\n",
"current_recommendation = {}\n",
"\n",
"# Gradio UI Functions\n",
"def fetch_market_data(symbol, sma_short_window, sma_long_window):\n",
" \"\"\"Fetch market data and calculate SMAs\"\"\"\n",
" global current_data, current_sma_short, current_sma_long, current_symbol, current_market_summary\n",
" \n",
" try:\n",
" current_symbol = symbol\n",
" \n",
" # Fetch data\n",
" data = data_fetcher.fetch_ohlcv(symbol, '1h', 720) # 30 days of hourly data\n",
" \n",
" if data.empty:\n",
" return None, \"❌ Failed to fetch market data\", \"No data available\", \"No data available\"\n",
" \n",
" # Calculate SMAs\n",
" sma_short = data_fetcher.calculate_sma(data, sma_short_window)\n",
" sma_long = data_fetcher.calculate_sma(data, sma_long_window)\n",
" \n",
" # Store in global state\n",
" current_data = data\n",
" current_sma_short = sma_short\n",
" current_sma_long = sma_long\n",
" \n",
" # Get market summary\n",
" current_market_summary = data_fetcher.get_market_summary(data, sma_short, sma_long)\n",
" \n",
" # Create chart\n",
" chart = chart_builder.create_candlestick_chart(data, sma_short, sma_long, symbol)\n",
" \n",
" # Prepare status message\n",
" status = f\"✅ Fetched {len(data)} records for {symbol}\"\n",
" status += f\"\\n📊 Current Price: ${current_market_summary.get('current_price', 0):.2f}\"\n",
" status += f\"\\n📈 Price Change: {current_market_summary.get('price_change_pct', 0):.2f}%\"\n",
" status += f\"\\n🔄 Crossover: {current_market_summary.get('crossover_status', 'Unknown')}\"\n",
" \n",
" # Market summary for display\n",
" sma_short = current_market_summary.get('sma_short')\n",
" sma_long = current_market_summary.get('sma_long')\n",
" \n",
" sma_short_str = f\"${sma_short:.2f}\" if sma_short is not None else \"N/A\"\n",
" sma_long_str = f\"${sma_long:.2f}\" if sma_long is not None else \"N/A\"\n",
" \n",
" summary = f\"\"\"\n",
"**Market Summary for {symbol}**\n",
"- Current Price: ${current_market_summary.get('current_price', 0):.2f}\n",
"- Price Change: {current_market_summary.get('price_change_pct', 0):.2f}%\n",
"- 5-Day Momentum: {current_market_summary.get('momentum_5d', 0):.2f}%\n",
"- Volume Ratio: {current_market_summary.get('volume_ratio', 1):.2f}x\n",
"- Short SMA: {sma_short_str}\n",
"- Long SMA: {sma_long_str}\n",
"- Crossover Status: {current_market_summary.get('crossover_status', 'Unknown')}\n",
"\"\"\"\n",
" \n",
" # Crossover status\n",
" crossover = current_market_summary.get('crossover_status', 'Unknown')\n",
" \n",
" return chart, status, summary, crossover\n",
" \n",
" except Exception as e:\n",
" return None, f\"❌ Error: {str(e)}\", \"Error occurred\", \"Error\"\n",
"\n",
"def get_trading_recommendation(model_name, temperature):\n",
" \"\"\"Get LLM trading recommendation\"\"\"\n",
" global current_market_summary, current_recommendation\n",
" \n",
" try:\n",
" if not current_market_summary:\n",
" return \"❌ No market data available. Please fetch data first.\", \"No data\", \"No data\", \"No data\"\n",
" \n",
" # Get recommendation from LLM\n",
" recommendation = trading_advisor.analyze_market(current_market_summary, model_name, temperature)\n",
" current_recommendation = recommendation\n",
" \n",
" # Format recommendation display\n",
" decision_emoji = trading_advisor.get_decision_emoji(recommendation['decision'])\n",
" confidence_color = trading_advisor.get_confidence_color(recommendation['confidence'])\n",
" \n",
" recommendation_text = f\"\"\"\n",
"**{decision_emoji} Trading Recommendation: {recommendation['decision']}**\n",
"\n",
"**Confidence:** {recommendation['confidence']}/10\n",
"**Risk Level:** {recommendation['risk_level']}\n",
"**Reasoning:** {recommendation['reasoning']}\n",
"\n",
"**Raw Analysis:**\n",
"{recommendation.get('raw_response', 'No raw response available')}\n",
"\"\"\"\n",
" \n",
" status = f\"✅ Analysis complete using {model_name}\"\n",
" return status, recommendation_text, recommendation['decision'], recommendation['confidence'], recommendation['reasoning']\n",
" \n",
" except Exception as e:\n",
" return f\"❌ Error getting recommendation: {str(e)}\", \"ERROR\", 0, \"Error occurred\"\n",
"\n",
"def execute_trade(trade_action, trade_amount):\n",
" \"\"\"Execute paper trade\"\"\"\n",
" global current_symbol, current_recommendation\n",
" \n",
" try:\n",
" if not current_recommendation:\n",
" return \"❌ No trading recommendation available. Please get analysis first.\", \"No recommendation\"\n",
" \n",
" if trade_action == \"SKIP\":\n",
" return \"⏭️ Trade skipped as requested\", \"Skipped\"\n",
" \n",
" # Determine trade side\n",
" if trade_action == \"BUY\" and current_recommendation['decision'] == 'BUY':\n",
" side = 'buy'\n",
" elif trade_action == \"SELL\" and current_recommendation['decision'] == 'SELL':\n",
" side = 'sell'\n",
" else:\n",
" return f\"⚠️ Trade action {trade_action} doesn't match recommendation {current_recommendation['decision']}\", \"Mismatch\"\n",
" \n",
" # Execute trade\n",
" result = paper_trader.place_order(current_symbol, side, trade_amount)\n",
" \n",
" print(result)\n",
"\n",
" if result['success']:\n",
" return result['message'], \"Success\"\n",
" else:\n",
" return result['message'], \"Failed\"\n",
" \n",
" except Exception as e:\n",
" return f\"❌ Trade execution error: {str(e)}\", \"Error\"\n",
"\n",
"def get_portfolio_status():\n",
" \"\"\"Get current portfolio status\"\"\"\n",
" try:\n",
" balance = paper_trader.get_balance()\n",
" portfolio_value = paper_trader.get_portfolio_value()\n",
" positions = paper_trader.get_positions()\n",
" trade_history = paper_trader.get_trade_history(10)\n",
" \n",
" # Format balance display\n",
" balance_text = f\"\"\"\n",
"**Portfolio Balance:**\n",
"- USD: ${balance['USD']:.2f}\n",
"- BTC: {balance['BTC']:.6f}\n",
"- ETH: {balance['ETH']:.6f}\n",
"- **Total Value: ${portfolio_value:.2f}**\n",
"\"\"\"\n",
" \n",
" # Format positions\n",
" if positions:\n",
" positions_text = \"**Current Positions:**\\n\"\n",
" for pos in positions:\n",
" positions_text += f\"- {pos['symbol']}: {pos['amount']:.6f} (${pos['value_usd']:.2f})\\n\"\n",
" else:\n",
" positions_text = \"**No current positions**\"\n",
" \n",
" # Format trade history\n",
" if trade_history:\n",
" history_df = pd.DataFrame(trade_history)\n",
" history_df['timestamp'] = pd.to_datetime(history_df['timestamp']).dt.strftime('%Y-%m-%d %H:%M')\n",
" history_df = history_df[['timestamp', 'symbol', 'side', 'amount', 'price', 'status']]\n",
" else:\n",
" history_df = pd.DataFrame(columns=['timestamp', 'symbol', 'side', 'amount', 'price', 'status'])\n",
" \n",
" return balance_text, positions_text, history_df\n",
" \n",
" except Exception as e:\n",
" return f\"❌ Error getting portfolio: {str(e)}\", \"Error\", pd.DataFrame()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3ba1f9a8",
"metadata": {},
"outputs": [],
"source": [
"# Create Gradio Interface\n",
"def create_trading_interface():\n",
" \"\"\"Create the main Gradio interface with three tabs\"\"\"\n",
" \n",
" with gr.Blocks(title=\"Crypto Trading System\", theme=gr.themes.Soft()) as interface:\n",
" \n",
" gr.Markdown(\"# 🚀 Crypto Trading System with AI Analysis\")\n",
" gr.Markdown(\"Fetch real-time crypto data, analyze with AI, and execute paper trades using Kraken API\")\n",
" \n",
" # Status bar\n",
" with gr.Row():\n",
" api_status = gr.Textbox(\n",
" label=\"API Status\",\n",
" value=\"✅ All systems ready\" if clients else \"❌ No API keys configured\",\n",
" interactive=False,\n",
" scale=1\n",
" )\n",
" portfolio_status = gr.Textbox(\n",
" label=\"Portfolio Status\",\n",
" value=\"Ready for trading\",\n",
" interactive=False,\n",
" scale=2\n",
" )\n",
" \n",
" # Tab 1: Market Data\n",
" with gr.Tab(\"📊 Market Data\"):\n",
" gr.Markdown(\"### Fetch and analyze crypto market data\")\n",
" \n",
" with gr.Row():\n",
" with gr.Column(scale=2):\n",
" symbol_input = gr.Dropdown(\n",
" choices=list(CRYPTO_PAIRS.keys()),\n",
" value=\"BTC/USD\",\n",
" label=\"Crypto Pair\"\n",
" )\n",
" \n",
" with gr.Row():\n",
" sma_short_input = gr.Number(\n",
" value=20,\n",
" minimum=5,\n",
" maximum=100,\n",
" step=1,\n",
" label=\"Short SMA Window\"\n",
" )\n",
" sma_long_input = gr.Number(\n",
" value=50,\n",
" minimum=10,\n",
" maximum=200,\n",
" step=1,\n",
" label=\"Long SMA Window\"\n",
" )\n",
" \n",
" fetch_btn = gr.Button(\"📊 Fetch Market Data\", variant=\"primary\", size=\"lg\")\n",
" \n",
" with gr.Column(scale=1):\n",
" market_status = gr.Textbox(\n",
" label=\"Fetch Status\",\n",
" lines=4,\n",
" interactive=False\n",
" )\n",
" \n",
" crossover_status = gr.Textbox(\n",
" label=\"Crossover Status\",\n",
" interactive=False\n",
" )\n",
" \n",
" # Chart display\n",
" chart_output = gr.Plot(\n",
" label=\"Price Chart with SMA Analysis\",\n",
" show_label=True\n",
" )\n",
" \n",
" # Market summary\n",
" market_summary = gr.Markdown(\n",
" label=\"Market Summary\",\n",
" value=\"No data loaded\"\n",
" )\n",
" \n",
" # Tab 2: Trading Analysis\n",
" with gr.Tab(\"🤖 AI Trading Analysis\"):\n",
" gr.Markdown(\"### Get AI-powered trading recommendations\")\n",
" \n",
" with gr.Row():\n",
" with gr.Column(scale=2):\n",
" analysis_model = gr.Dropdown(\n",
" choices=list(MODELS.keys()),\n",
" value=list(MODELS.keys())[0],\n",
" label=\"AI Model\"\n",
" )\n",
" \n",
" analysis_temperature = gr.Slider(\n",
" minimum=0.0,\n",
" maximum=1.0,\n",
" value=0.3,\n",
" step=0.1,\n",
" label=\"Temperature (Lower = More Consistent)\"\n",
" )\n",
" \n",
" analyze_btn = gr.Button(\"🤖 Get AI Recommendation\", variant=\"primary\", size=\"lg\")\n",
" \n",
" with gr.Column(scale=1):\n",
" analysis_status = gr.Textbox(\n",
" label=\"Analysis Status\",\n",
" lines=2,\n",
" interactive=False\n",
" )\n",
" \n",
" # Analysis results\n",
" recommendation_display = gr.Markdown(\n",
" label=\"Trading Recommendation\",\n",
" value=\"No analysis performed yet\"\n",
" )\n",
" \n",
" with gr.Row():\n",
" decision_output = gr.Textbox(\n",
" label=\"Decision\",\n",
" interactive=False\n",
" )\n",
" confidence_output = gr.Number(\n",
" label=\"Confidence (1-10)\",\n",
" interactive=False\n",
" )\n",
" reasoning_output = gr.Textbox(\n",
" label=\"Reasoning\",\n",
" lines=3,\n",
" interactive=False\n",
" )\n",
" \n",
" # Tab 3: Paper Trading\n",
" with gr.Tab(\"💰 Paper Trading\"):\n",
" gr.Markdown(\"### Execute paper trades based on AI recommendations\")\n",
" \n",
" with gr.Row():\n",
" with gr.Column(scale=2):\n",
" # Portfolio status\n",
" portfolio_balance = gr.Markdown(\n",
" label=\"Portfolio Balance\",\n",
" value=\"Loading portfolio...\"\n",
" )\n",
" \n",
" portfolio_positions = gr.Markdown(\n",
" label=\"Current Positions\",\n",
" value=\"No positions\"\n",
" )\n",
" \n",
" # Trade execution\n",
" trade_action = gr.Radio(\n",
" choices=[\"BUY\", \"SELL\", \"SKIP\"],\n",
" value=\"SKIP\",\n",
" label=\"Trade Action\"\n",
" )\n",
" \n",
" trade_amount = gr.Number(\n",
" value=5,\n",
" minimum=1.0,\n",
" maximum=100.0,\n",
" step=1,\n",
" label=\"Trade Amount in USD (BTC/ETH)\"\n",
" )\n",
" \n",
" execute_btn = gr.Button(\"💰 Execute Trade\", variant=\"primary\", size=\"lg\")\n",
" \n",
" trade_result = gr.Textbox(\n",
" label=\"Trade Result\",\n",
" lines=3,\n",
" interactive=False\n",
" )\n",
" trade_status = gr.Textbox(\n",
" label=\"Trade Status\",\n",
" interactive=False,\n",
" visible=False \n",
" )\n",
" \n",
" with gr.Column(scale=1):\n",
" # Trade history\n",
" trade_history = gr.Dataframe(\n",
" label=\"Recent Trades\",\n",
" interactive=False,\n",
" wrap=True\n",
" )\n",
" \n",
" refresh_portfolio_btn = gr.Button(\"🔄 Refresh Portfolio\", variant=\"secondary\")\n",
" \n",
" # Event handlers\n",
" fetch_btn.click(\n",
" fetch_market_data,\n",
" inputs=[symbol_input, sma_short_input, sma_long_input],\n",
" outputs=[chart_output, market_status, market_summary, crossover_status]\n",
" )\n",
" \n",
" analyze_btn.click(\n",
" get_trading_recommendation,\n",
" inputs=[analysis_model, analysis_temperature],\n",
" outputs=[analysis_status, recommendation_display, decision_output, confidence_output, reasoning_output]\n",
" )\n",
" \n",
" execute_btn.click(\n",
" execute_trade,\n",
" inputs=[trade_action, trade_amount],\n",
" outputs=[trade_result, trade_status]\n",
" )\n",
" \n",
" refresh_portfolio_btn.click(\n",
" get_portfolio_status,\n",
" outputs=[portfolio_balance, portfolio_positions, trade_history]\n",
" )\n",
" \n",
" # Auto-refresh portfolio on load\n",
" interface.load(\n",
" get_portfolio_status,\n",
" outputs=[portfolio_balance, portfolio_positions, trade_history]\n",
" )\n",
" \n",
" return interface\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1b040594",
"metadata": {},
"outputs": [],
"source": [
"# Launch the Trading System\n",
"interface = create_trading_interface()\n",
"\n",
"interface.launch(\n",
" server_name=\"0.0.0.0\",\n",
" server_port=7860\n",
")\n"
]
},
{
"cell_type": "markdown",
"id": "580a4048",
"metadata": {},
"source": [
"## Testing and Validation\n",
"\n",
"### Quick Test Functions\n",
"\n",
"Run these cells to test individual components:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2ea5bfeb",
"metadata": {},
"outputs": [],
"source": [
"# Test 1: Data Fetching\n",
"print(\"🧪 Testing Data Fetching...\")\n",
"test_data = data_fetcher.fetch_ohlcv(\"BTC/USD\", \"1h\", 24) # Last 24 hours\n",
"if not test_data.empty:\n",
" print(f\"✅ Data fetch successful: {len(test_data)} records\")\n",
" print(f\" Latest price: ${test_data['close'].iloc[-1]:.2f}\")\n",
" \n",
" # Test SMA calculation\n",
" sma_20 = data_fetcher.calculate_sma(test_data, 20)\n",
" sma_50 = data_fetcher.calculate_sma(test_data, 50)\n",
" print(f\"✅ SMA calculation successful\")\n",
" print(f\" SMA 20: ${sma_20.iloc[-1]:.2f}\" if not sma_20.empty else \" SMA 20: N/A\")\n",
" print(f\" SMA 50: ${sma_50.iloc[-1]:.2f}\" if not sma_50.empty else \" SMA 50: N/A\")\n",
" \n",
" # Test crossover detection\n",
" crossover = data_fetcher.detect_crossover(sma_20, sma_50)\n",
" print(f\"✅ Crossover detection: {crossover}\")\n",
"else:\n",
" print(\"❌ Data fetch failed\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "eb983b26",
"metadata": {},
"outputs": [],
"source": [
"# Test 2: Chart Generation\n",
"print(\"\\n🧪 Testing Chart Generation...\")\n",
"if not test_data.empty:\n",
" try:\n",
" test_chart = chart_builder.create_candlestick_chart(test_data, sma_20, sma_50, \"BTC/USD\")\n",
" print(\"✅ Chart generation successful\")\n",
" print(f\" Chart type: {type(test_chart)}\")\n",
" print(f\" Data points: {len(test_data)}\")\n",
" except Exception as e:\n",
" print(f\"❌ Chart generation failed: {str(e)}\")\n",
"else:\n",
" print(\"❌ No data available for chart testing\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e58aab73",
"metadata": {},
"outputs": [],
"source": [
"# Test 3: LLM Trading Analysis\n",
"print(\"\\n🧪 Testing LLM Trading Analysis...\")\n",
"if not test_data.empty and clients:\n",
" try:\n",
" # Get market summary\n",
" market_summary = data_fetcher.get_market_summary(test_data, sma_20, sma_50)\n",
" print(f\"✅ Market summary generated: {len(market_summary)} fields\")\n",
" \n",
" # Test LLM analysis (use first available model)\n",
" available_models = [name for name, info in MODELS.items() if info['provider'] in clients]\n",
" if available_models:\n",
" model_name = available_models[0]\n",
" print(f\" Testing with model: {model_name}\")\n",
" \n",
" recommendation = trading_advisor.analyze_market(market_summary, model_name, 0.3)\n",
" print(f\"✅ LLM analysis successful\")\n",
" print(f\" Decision: {recommendation['decision']}\")\n",
" print(f\" Confidence: {recommendation['confidence']}/10\")\n",
" print(f\" Risk Level: {recommendation['risk_level']}\")\n",
" else:\n",
" print(\"❌ No LLM models available\")\n",
" except Exception as e:\n",
" print(f\"❌ LLM analysis failed: {str(e)}\")\n",
"else:\n",
" print(\"❌ No data or LLM clients available for testing\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "71c87193",
"metadata": {},
"outputs": [],
"source": [
"# Test 4: Real Kraken Sandbox Trading\n",
"print(\"\\n🧪 Testing Real Kraken Sandbox Trading...\")\n",
"try:\n",
" # Test portfolio status\n",
" balance = paper_trader.get_balance()\n",
" portfolio_value = paper_trader.get_portfolio_value()\n",
" print(f\"✅ Portfolio status retrieved from Kraken sandbox\")\n",
" print(f\" USD Balance: ${balance['USD']:.2f}\")\n",
" print(f\" BTC Balance: {balance['BTC']:.6f}\")\n",
" print(f\" ETH Balance: {balance['ETH']:.6f}\")\n",
" print(f\" Total Value: ${portfolio_value:.2f}\")\n",
" \n",
" # Test real trade (very small amount to avoid issues)\n",
" if balance['USD'] > 10: # Only test if we have some USD balance\n",
" test_result = paper_trader.place_order(\"BTC/USD\", \"sell\", 5)\n",
" if test_result['success']:\n",
" print(f\"✅ Real trade successful: {test_result['message']}\")\n",
" \n",
" # Check updated balance\n",
" new_balance = paper_trader.get_balance()\n",
" print(f\" Updated USD: ${new_balance['USD']:.2f}\")\n",
" print(f\" Updated BTC: {new_balance['BTC']:.6f}\")\n",
" else:\n",
" print(f\"❌ Real trade failed: {test_result['message']}\")\n",
" else:\n",
" print(\"⚠️ Insufficient USD balance for testing real trades\")\n",
" print(\" Note: Kraken sandbox may require initial funding\")\n",
" \n",
" # Test trade history\n",
" trade_history = paper_trader.get_trade_history(5)\n",
" print(f\"✅ Trade history retrieved: {len(trade_history)} recent trades\")\n",
" \n",
" # Test positions\n",
" positions = paper_trader.get_positions()\n",
" print(f\"✅ Current positions: {len(positions)} active positions\")\n",
" for pos in positions:\n",
" print(f\" {pos['symbol']}: {pos['amount']:.6f} (${pos['value_usd']:.2f})\")\n",
" \n",
"except Exception as e:\n",
" print(f\"❌ Real trading test failed: {str(e)}\")\n",
"\n",
"print(\"\\n🎉 All tests completed!\")\n",
"print(\"=\" * 50)\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}