| import os |
| import sys |
| import time |
| import json |
| import gradio as gr |
| import threading |
| import pandas as pd |
| import numpy as np |
| from datetime import datetime, timedelta |
| import matplotlib.pyplot as plt |
| import requests |
| import sqlite3 |
| from typing import Dict, Any, List, Optional |
| import openai |
|
|
| |
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) |
|
|
| |
| from src.crypto_analysis.tools.technical_tools import TechnicalAnalysisStrategy, IndicatorCalculator |
| from src.crypto_analysis.tools.order_tools import AlpacaCryptoOrderTool |
| from src.crypto_analysis.tools.bitcoin_tools import YahooBitcoinDataTool |
| from src.crypto_analysis.tools.yahoo_tools import YahooCryptoMarketTool |
| from src.crypto_analysis.crew import BitcoinAnalysisCrew |
|
|
| |
| from dotenv import load_dotenv |
| load_dotenv() |
|
|
| |
| DB_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../data/cryptic.db')) |
| os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) |
|
|
| def init_database(): |
| """Initialize the SQLite database with necessary tables""" |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| |
| |
| cursor.execute(''' |
| CREATE TABLE IF NOT EXISTS strategies ( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| name TEXT NOT NULL UNIQUE, |
| description TEXT, |
| strategy_text TEXT NOT NULL, |
| parameters TEXT NOT NULL, |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
| ) |
| ''') |
| |
| |
| cursor.execute(''' |
| CREATE TABLE IF NOT EXISTS transactions ( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| symbol TEXT NOT NULL, |
| action TEXT NOT NULL, |
| quantity REAL NOT NULL, |
| price REAL NOT NULL, |
| status TEXT NOT NULL, |
| allocation_percentage INTEGER, |
| order_id TEXT, |
| strategy_id INTEGER, |
| reasoning TEXT, |
| timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
| FOREIGN KEY (strategy_id) REFERENCES strategies (id) |
| ) |
| ''') |
| |
| |
| cursor.execute(''' |
| CREATE TABLE IF NOT EXISTS analysis_results ( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| signal TEXT NOT NULL, |
| confidence INTEGER, |
| allocation_percentage INTEGER, |
| reasoning TEXT, |
| indicator_values TEXT, |
| strategy_id INTEGER, |
| timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
| FOREIGN KEY (strategy_id) REFERENCES strategies (id) |
| ) |
| ''') |
| |
| conn.commit() |
| conn.close() |
|
|
| |
| init_database() |
|
|
| |
| strategy_params = { |
| "timeframe_minutes": 60, |
| "max_allocation_percentage": 5, |
| "strategy_text": None |
| } |
|
|
| |
| analysis_results = [] |
| orders_history = [] |
| active_trades = [] |
|
|
| |
| running = False |
| background_thread = None |
|
|
| |
| def get_saved_strategies(): |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| cursor.execute("SELECT id, name, description FROM strategies") |
| strategies = [{"id": row[0], "name": row[1], "description": row[2]} for row in cursor.fetchall()] |
| conn.close() |
| return strategies |
|
|
| |
| def get_strategy_by_id(strategy_id): |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| cursor.execute("SELECT id, name, description, strategy_text, parameters FROM strategies WHERE id = ?", (strategy_id,)) |
| row = cursor.fetchone() |
| conn.close() |
| |
| if row: |
| return { |
| "id": row[0], |
| "name": row[1], |
| "description": row[2], |
| "strategy_text": row[3], |
| "parameters": json.loads(row[4]) |
| } |
| return None |
|
|
| |
| def save_strategy(name, description, strategy_text, parameters): |
| try: |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| |
| |
| cursor.execute("SELECT id FROM strategies WHERE name = ?", (name,)) |
| existing = cursor.fetchone() |
| |
| if existing: |
| |
| cursor.execute( |
| "UPDATE strategies SET description = ?, strategy_text = ?, parameters = ? WHERE name = ?", |
| (description, strategy_text, json.dumps(parameters), name) |
| ) |
| else: |
| |
| cursor.execute( |
| "INSERT INTO strategies (name, description, strategy_text, parameters) VALUES (?, ?, ?, ?)", |
| (name, strategy_text, strategy_text, json.dumps(parameters)) |
| ) |
| |
| conn.commit() |
| conn.close() |
| return True, "Strategy saved successfully" |
| except Exception as e: |
| return False, f"Error saving strategy: {str(e)}" |
|
|
| |
| def save_analysis_result(result, strategy_id=None): |
| try: |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| |
| |
| signal = result.get("signal", "unknown") |
| confidence = result.get("confidence", 0) |
| allocation_percentage = result.get("allocation_percentage", 0) |
| reasoning = result.get("reasoning", "") |
| |
| |
| indicator_values = json.dumps(result.get("technical_indicators", {})) |
| |
| |
| cursor.execute( |
| "INSERT INTO analysis_results (signal, confidence, allocation_percentage, reasoning, indicator_values, strategy_id) VALUES (?, ?, ?, ?, ?, ?)", |
| (signal, confidence, allocation_percentage, reasoning, indicator_values, strategy_id) |
| ) |
| |
| conn.commit() |
| conn.close() |
| return True |
| except Exception as e: |
| print(f"Error saving analysis result: {e}") |
| return False |
|
|
| |
| def save_transaction(order_data, strategy_id=None): |
| try: |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| |
| |
| symbol = order_data.get("symbol", "BTC/USD") |
| action = order_data.get("action", "unknown") |
| quantity = order_data.get("quantity", 0) |
| price = order_data.get("price", 0) |
| status = order_data.get("status", "unknown") |
| allocation_percentage = order_data.get("allocation_percentage", 0) |
| order_id = order_data.get("order_id", "") |
| reasoning = order_data.get("reasoning", "") |
| |
| |
| cursor.execute( |
| "INSERT INTO transactions (symbol, action, quantity, price, status, allocation_percentage, order_id, strategy_id, reasoning) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", |
| (symbol, action, quantity, price, status, allocation_percentage, order_id, strategy_id, reasoning) |
| ) |
| |
| conn.commit() |
| conn.close() |
| return True |
| except Exception as e: |
| print(f"Error saving transaction: {e}") |
| return False |
|
|
| |
| def get_recent_analysis_results(limit=10, full_details=False): |
| conn = sqlite3.connect(DB_PATH) |
| conn.row_factory = sqlite3.Row |
| cursor = conn.cursor() |
| |
| if full_details: |
| |
| cursor.execute(""" |
| SELECT ar.*, s.name as strategy_name |
| FROM analysis_results ar |
| LEFT JOIN strategies s ON ar.strategy_id = s.id |
| ORDER BY ar.timestamp DESC |
| LIMIT 1 |
| """) |
| |
| row = cursor.fetchone() |
| conn.close() |
| |
| if not row: |
| return None |
| |
| |
| result = dict(row) |
| |
| |
| if "indicator_values" in result and result["indicator_values"]: |
| try: |
| result["technical_indicators"] = json.loads(result["indicator_values"]) |
| except json.JSONDecodeError: |
| result["technical_indicators"] = {} |
| |
| return result |
| else: |
| |
| cursor.execute(""" |
| SELECT ar.id, ar.signal, ar.confidence, ar.allocation_percentage, ar.reasoning, |
| ar.timestamp, s.name as strategy_name |
| FROM analysis_results ar |
| LEFT JOIN strategies s ON ar.strategy_id = s.id |
| ORDER BY ar.timestamp DESC |
| LIMIT ? |
| """, (limit,)) |
| |
| results = [] |
| for row in cursor.fetchall(): |
| results.append(dict(row)) |
| |
| conn.close() |
| return results |
|
|
| |
| def get_recent_transactions(limit=10): |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| cursor.execute(""" |
| SELECT t.id, t.symbol, t.action, t.quantity, t.price, t.status, |
| t.allocation_percentage, t.timestamp, s.name as strategy_name |
| FROM transactions t |
| LEFT JOIN strategies s ON t.strategy_id = s.id |
| ORDER BY t.timestamp DESC |
| LIMIT ? |
| """, (limit,)) |
| |
| transactions = [] |
| for row in cursor.fetchall(): |
| transactions.append({ |
| "id": row[0], |
| "symbol": row[1], |
| "action": row[2], |
| "quantity": row[3], |
| "price": row[4], |
| "status": row[5], |
| "allocation_percentage": row[6], |
| "timestamp": row[7], |
| "strategy_name": row[8] or "Default Strategy" |
| }) |
| |
| conn.close() |
| return transactions |
|
|
| |
| def fetch_account_info(): |
| try: |
| order_tool = AlpacaCryptoOrderTool() |
| account_data = order_tool._check_account() |
| return account_data |
| except Exception as e: |
| print(f"Error fetching account info: {e}") |
| return {"error": str(e), "cash": 0, "equity": 0} |
|
|
| |
| def reset_portfolio(): |
| try: |
| |
| api_key = os.getenv("ALPACA_API_KEY") |
| api_secret = os.getenv("ALPACA_API_SECRET") |
| |
| headers = { |
| "APCA-API-KEY-ID": api_key, |
| "APCA-API-SECRET-KEY": api_secret |
| } |
| |
| |
| base_url = "https://paper-api.alpaca.markets" |
| |
| |
| response = requests.delete(f"{base_url}/v2/orders", headers=headers) |
| if response.status_code != 204 and response.status_code != 200: |
| print(f"Error canceling orders: {response.status_code}, {response.text}") |
| return f"Error canceling orders: {response.status_code}" |
| |
| |
| response = requests.delete(f"{base_url}/v2/positions", headers=headers) |
| if response.status_code != 204 and response.status_code != 200: |
| print(f"Error closing positions: {response.status_code}, {response.text}") |
| return f"Error closing positions: {response.status_code}" |
| |
| return "Portfolio reset successfully. All positions closed and orders canceled." |
| except Exception as e: |
| print(f"Error resetting portfolio: {e}") |
| return f"Error resetting portfolio: {str(e)}" |
|
|
| |
| def fetch_order_history(): |
| try: |
| |
| api_key = os.getenv("ALPACA_API_KEY") |
| api_secret = os.getenv("ALPACA_API_SECRET") |
| |
| headers = { |
| "APCA-API-KEY-ID": api_key, |
| "APCA-API-SECRET-KEY": api_secret |
| } |
| |
| |
| base_url = "https://paper-api.alpaca.markets" |
| |
| |
| response = requests.get(f"{base_url}/v2/orders?status=all&limit=100", headers=headers) |
| |
| if response.status_code == 200: |
| orders = response.json() |
| |
| btc_orders = [order for order in orders if "BTC" in order.get("symbol", "")] |
| |
| formatted_orders = [] |
| for order in btc_orders: |
| formatted_orders.append({ |
| "id": order["id"], |
| "symbol": order["symbol"], |
| "side": order["side"], |
| "type": order["type"], |
| "qty": order["qty"], |
| "status": order["status"], |
| "created_at": order["created_at"], |
| "filled_at": order.get("filled_at", "N/A"), |
| "filled_qty": order.get("filled_qty", "0"), |
| "filled_avg_price": order.get("filled_avg_price", "0") |
| }) |
| |
| return formatted_orders |
| else: |
| print(f"Error fetching orders: {response.status_code}, {response.text}") |
| return [] |
| except Exception as e: |
| print(f"Error in fetch_order_history: {e}") |
| return [] |
|
|
| |
| def fetch_active_positions(): |
| try: |
| api_key = os.getenv("ALPACA_API_KEY") |
| api_secret = os.getenv("ALPACA_API_SECRET") |
| |
| headers = { |
| "APCA-API-KEY-ID": api_key, |
| "APCA-API-SECRET-KEY": api_secret |
| } |
| |
| base_url = "https://paper-api.alpaca.markets" |
| |
| |
| response = requests.get(f"{base_url}/v2/positions", headers=headers) |
| |
| if response.status_code == 200: |
| positions = response.json() |
| |
| btc_positions = [pos for pos in positions if "BTC" in pos.get("symbol", "")] |
| |
| formatted_positions = [] |
| for pos in btc_positions: |
| |
| current_price = float(pos.get("current_price", 0)) |
| avg_entry_price = float(pos.get("avg_entry_price", 0)) |
| qty = float(pos.get("qty", 0)) |
| |
| profit_loss = (current_price - avg_entry_price) * qty |
| profit_loss_percent = ((current_price / avg_entry_price) - 1) * 100 if avg_entry_price > 0 else 0 |
| |
| formatted_positions.append({ |
| "symbol": pos["symbol"], |
| "qty": pos["qty"], |
| "avg_entry_price": pos["avg_entry_price"], |
| "current_price": pos["current_price"], |
| "profit_loss": round(profit_loss, 2), |
| "profit_loss_percent": round(profit_loss_percent, 2), |
| "market_value": pos["market_value"], |
| "side": pos["side"] |
| }) |
| |
| return formatted_positions |
| else: |
| print(f"Error fetching positions: {response.status_code}, {response.text}") |
| return [] |
| except Exception as e: |
| print(f"Error in fetch_active_positions: {e}") |
| return [] |
|
|
| |
| def run_ta_agent_only(strategy_text=None): |
| try: |
| |
| timeframe_minutes = strategy_params.get("timeframe_minutes", 60) |
| if timeframe_minutes < 60: |
| timeframe = f"{timeframe_minutes}m" |
| else: |
| hours = timeframe_minutes // 60 |
| timeframe = f"{hours}h" |
| |
| |
| tech_strategy = TechnicalAnalysisStrategy(timeframe=timeframe) |
| |
| |
| strategy_text = strategy_text or strategy_params.get("strategy_text") |
| |
| if not strategy_text: |
| return { |
| "error": "No strategy text provided", |
| "signal": "hold", |
| "confidence": 0, |
| "allocation_percentage": 0, |
| "reasoning": "Please enter a strategy description first" |
| } |
| |
| |
| indicator_data = tech_strategy._run() |
| |
| if "error" in indicator_data: |
| return { |
| "error": indicator_data["error"], |
| "signal": "hold", |
| "confidence": 0, |
| "allocation_percentage": 0, |
| "reasoning": f"Error fetching indicator data: {indicator_data['error']}" |
| } |
| |
| |
| signal_data = interpret_strategy_with_llm(indicator_data, strategy_text, strategy_params["max_allocation_percentage"]) |
| |
| |
| signal_data["timestamp"] = datetime.now().isoformat() |
| |
| |
| analysis_results.append(signal_data) |
| |
| |
| save_analysis_result(signal_data) |
| |
| return signal_data |
| except Exception as e: |
| print(f"Error running TA agent: {e}") |
| return {"error": str(e)} |
|
|
| |
| def interpret_strategy_with_llm(indicator_data, strategy_text, max_allocation_percentage=50): |
| try: |
| |
| system_prompt = """ |
| You are a cryptocurrency trading strategy interpreter. Your task is to analyze the provided technical |
| indicators and price data, then interpret the user's strategy to generate a trading signal. |
| |
| You must return a JSON object with the following fields: |
| - signal: "buy", "sell", or "hold" |
| - confidence: Integer between 0-95 (how confident you are in the signal) |
| - allocation_percentage: Integer between 0-{max_allocation} (how much of the portfolio to allocate) |
| - reasoning: String explanation of your decision process |
| |
| Be pragmatic and conservative. Only give buy/sell signals when the conditions are clearly met. |
| Base your decision on the indicator values, not on general market sentiment or news. |
| """ |
| |
| |
| price = indicator_data.get("price", 0) |
| |
| |
| user_prompt = f""" |
| # Technical Indicators |
| {json.dumps(indicator_data, indent=2)} |
| |
| # Strategy Description |
| {strategy_text} |
| |
| Analyze the above data according to the strategy description and generate a trading signal. |
| Respond only with JSON. Maximum allocation is {max_allocation_percentage}%. |
| """ |
| |
| |
| response = openai.chat.completions.create( |
| model="gpt-3.5-turbo", |
| messages=[ |
| {"role": "system", "content": system_prompt.format(max_allocation=max_allocation_percentage)}, |
| {"role": "user", "content": user_prompt} |
| ], |
| temperature=0.2, |
| response_format={"type": "json_object"} |
| ) |
| |
| |
| response_content = response.choices[0].message.content |
| result = json.loads(response_content) |
| |
| |
| if not all(k in result for k in ["signal", "confidence", "allocation_percentage", "reasoning"]): |
| missing = [k for k in ["signal", "confidence", "allocation_percentage", "reasoning"] if k not in result] |
| print(f"LLM response missing required fields: {missing}") |
| result = { |
| "signal": result.get("signal", "hold"), |
| "confidence": result.get("confidence", 50), |
| "allocation_percentage": result.get("allocation_percentage", 0), |
| "reasoning": result.get("reasoning", "No reasoning provided.") |
| } |
| |
| |
| result["confidence"] = max(0, min(95, int(result["confidence"]))) |
| result["allocation_percentage"] = max(0, min(max_allocation_percentage, int(result["allocation_percentage"]))) |
| |
| |
| result["technical_indicators"] = indicator_data |
| |
| print(f"LLM generated signal: {result['signal']} with confidence {result['confidence']}%") |
| return result |
| |
| except Exception as e: |
| print(f"Error interpreting strategy with LLM: {e}") |
| import traceback |
| traceback.print_exc() |
| return { |
| "signal": "hold", |
| "confidence": 0, |
| "allocation_percentage": 0, |
| "reasoning": f"Error interpreting strategy with LLM: {str(e)}" |
| } |
|
|
| |
| def run_full_analysis(): |
| try: |
| |
| strategy_text = strategy_params.get("strategy_text") |
| |
| if not strategy_text: |
| return { |
| "error": "No strategy text provided", |
| "signal": "hold", |
| "confidence": 0, |
| "allocation_percentage": 0, |
| "reasoning": "Please enter a strategy description first" |
| } |
| |
| |
| timeframe_minutes = strategy_params.get("timeframe_minutes", 60) |
| |
| if timeframe_minutes < 60: |
| timeframe = f"{timeframe_minutes}m" |
| else: |
| hours = timeframe_minutes // 60 |
| timeframe = f"{hours}h" |
| |
| |
| max_allocation = strategy_params.get("max_allocation_percentage", 5) |
| |
| |
| crew = BitcoinAnalysisCrew(timeframe=timeframe, max_allocation=max_allocation) |
| |
| print(f"Running analysis with timeframe={timeframe}, max_allocation={max_allocation}%") |
| result = crew.run_analysis(strategy_text=strategy_text) |
| |
| |
| result["timestamp"] = datetime.now().isoformat() |
| |
| |
| analysis_results.append(result) |
| |
| |
| save_analysis_result(result) |
| |
| |
| if "order_execution" in result and isinstance(result["order_execution"], dict): |
| if result["order_execution"].get("success", False): |
| orders_history.append(result["order_execution"]) |
| save_transaction(result["order_execution"]) |
| |
| return result |
| except Exception as e: |
| print(f"Error running crew analysis: {e}") |
| return {"error": str(e)} |
|
|
| |
| def background_process(): |
| global running |
| |
| |
| log_file = os.path.join(os.path.dirname(DB_PATH), f"auto_trading_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt") |
| with open(log_file, 'w') as f: |
| f.write(f"Automated trading session started at {datetime.now().isoformat()}\n") |
| f.write(f"Strategy parameters: {json.dumps(strategy_params)}\n\n") |
| |
| error_count = 0 |
| max_errors = 5 |
| |
| while running: |
| try: |
| print(f"Running full crew analysis at {datetime.now().isoformat()} with params: {strategy_params}") |
| |
| |
| with open(log_file, 'a') as f: |
| f.write(f"\n--- Analysis run at {datetime.now().isoformat()} ---\n") |
| |
| |
| if not strategy_params.get("strategy_text"): |
| print("No strategy text available for automated analysis. Skipping.") |
| with open(log_file, 'a') as f: |
| f.write("No strategy text available for automated analysis. Skipping.\n") |
| time.sleep(60) |
| continue |
| |
| |
| result = run_full_analysis() |
| print(f"Analysis result: {result.get('signal', 'unknown')} with confidence {result.get('confidence', 0)}%") |
| |
| |
| with open(log_file, 'a') as f: |
| f.write(f"Signal: {result.get('signal', 'unknown')}, Confidence: {result.get('confidence', 0)}%, Allocation: {result.get('allocation_percentage', 0)}%\n") |
| f.write(f"Reasoning: {result.get('reasoning', 'No reasoning provided')}\n") |
| |
| |
| if "order_execution" in result and result["order_execution"]: |
| order_details = result["order_execution"] |
| if isinstance(order_details, dict): |
| f.write(f"Order executed: {order_details.get('action', 'unknown')} {order_details.get('quantity', 0)} BTC at ${order_details.get('price', 0)}\n") |
| else: |
| f.write(f"Order info: {str(order_details)}\n") |
| |
| |
| positions = fetch_active_positions() |
| global active_trades |
| active_trades = positions |
| |
| |
| with open(log_file, 'a') as f: |
| f.write("\nCurrent Positions:\n") |
| if positions: |
| for pos in positions: |
| f.write(f" {pos['symbol']}: {pos['qty']} @ ${pos['avg_entry_price']} - P/L: ${pos['profit_loss']} ({pos['profit_loss_percent']}%)\n") |
| else: |
| f.write(" No active positions\n") |
| |
| |
| account = fetch_account_info() |
| f.write(f"\nAccount Balance: ${account.get('cash', 'N/A')}, Equity: ${account.get('equity', 'N/A')}\n") |
| |
| |
| error_count = 0 |
| |
| |
| interval_seconds = strategy_params["timeframe_minutes"] * 60 |
| print(f"Sleeping for {interval_seconds} seconds ({strategy_params['timeframe_minutes']} minutes)") |
| |
| |
| for _ in range(min(interval_seconds, 3600), 0, -10): |
| if not running: |
| break |
| time.sleep(10) |
| |
| except Exception as e: |
| error_count += 1 |
| error_message = f"Error in background process: {str(e)}" |
| print(error_message) |
| import traceback |
| trace = traceback.format_exc() |
| print(trace) |
| |
| |
| with open(log_file, 'a') as f: |
| f.write(f"\nERROR: {error_message}\n") |
| f.write(trace + "\n") |
| |
| |
| if error_count >= max_errors: |
| print(f"Too many errors ({error_count}). Pausing for 30 minutes.") |
| with open(log_file, 'a') as f: |
| f.write(f"Too many errors ({error_count}). Pausing for 30 minutes.\n") |
| |
| |
| for _ in range(1800, 0, -10): |
| if not running: |
| break |
| time.sleep(10) |
| |
| |
| error_count = 0 |
| else: |
| |
| time.sleep(60) |
|
|
| |
| def start_background_process(): |
| global running, background_thread |
| |
| if not running: |
| running = True |
| background_thread = threading.Thread(target=background_process) |
| background_thread.daemon = True |
| background_thread.start() |
| return f"Background analysis started. Running full crew analysis every {strategy_params['timeframe_minutes']} minutes." |
| else: |
| return "Background analysis is already running." |
|
|
| |
| def stop_background_process(): |
| global running |
| |
| if running: |
| running = False |
| return "Background analysis stopped." |
| else: |
| return "Background analysis is not running." |
|
|
| |
| def update_strategy(timeframe, max_allocation): |
| global strategy_params |
| |
| try: |
| |
| timeframe = int(timeframe) |
| max_allocation = int(max_allocation) |
| |
| |
| strategy_params["timeframe_minutes"] = timeframe |
| strategy_params["max_allocation_percentage"] = max_allocation |
| |
| print(f"Updated strategy parameters: {strategy_params}") |
| |
| return f"Strategy parameters updated: Timeframe: {timeframe} minutes, Max allocation: {max_allocation}%" |
| except Exception as e: |
| return f"Error updating strategy parameters: {e}" |
|
|
| |
| def update_strategy_text(strategy_text): |
| global strategy_params |
| |
| try: |
| strategy_params["strategy_text"] = strategy_text |
| print(f"Updated strategy text: {strategy_text[:100]}...") |
| return "Strategy text updated successfully" |
| except Exception as e: |
| return f"Error updating strategy text: {e}" |
|
|
| |
| def save_current_strategy(name, description): |
| try: |
| |
| parameters = strategy_params.copy() |
| strategy_text = parameters.get("strategy_text", "") |
| |
| |
| if not strategy_text: |
| strategy_text = f"Default RSI ({parameters['rsi_lower_threshold']}-{parameters['rsi_upper_threshold']}) and Bollinger Bands strategy" |
| |
| |
| success, message = save_strategy(name, description, strategy_text, parameters) |
| |
| if success: |
| return f"Strategy '{name}' saved successfully" |
| else: |
| return message |
| except Exception as e: |
| return f"Error saving strategy: {e}" |
|
|
| |
| def execute_trade(action, symbol, allocation_pct): |
| try: |
| order_tool = AlpacaCryptoOrderTool() |
| |
| result = order_tool._run( |
| action=action, |
| symbol=symbol, |
| allocation_percentage=int(allocation_pct) |
| ) |
| |
| if result.get("success", False): |
| orders_history.append(result) |
| |
| save_transaction(result) |
| return f"Trade executed: {action.upper()} {symbol} with {allocation_pct}% allocation" |
| else: |
| return f"Trade failed: {result.get('error', 'Unknown error')}" |
| except Exception as e: |
| return f"Error executing trade: {e}" |
|
|
| |
| def get_account_summary(): |
| account = fetch_account_info() |
| positions = fetch_active_positions() |
| |
| cash = account.get("cash", "0") |
| equity = account.get("equity", "0") |
| |
| total_positions = len(positions) |
| total_value = sum(float(pos.get("market_value", 0)) for pos in positions) |
| total_pl = sum(pos.get("profit_loss", 0) for pos in positions) |
| |
| return f""" |
| **Account Summary** |
| - Cash: ${cash} |
| - Equity: ${equity} |
| - Active Positions: {total_positions} |
| - Positions Value: ${total_value:.2f} |
| - Total P/L: ${total_pl:.2f} |
| """ |
|
|
| |
| def format_analysis_results(): |
| |
| db_results = get_recent_analysis_results(1) |
| |
| if db_results: |
| latest = db_results[0] |
| |
| timestamp = latest.get("timestamp", datetime.now().isoformat()) |
| signal = latest.get("signal", "unknown").upper() |
| confidence = latest.get("confidence", 0) |
| allocation = latest.get("allocation_percentage", 0) |
| reasoning = latest.get("reasoning", "No reasoning provided.") |
| strategy_name = latest.get("strategy_name", "Default Strategy") |
| |
| return f""" |
| **Latest Analysis ({timestamp})** |
| |
| Strategy: {strategy_name} |
| Signal: {signal} |
| Confidence: {confidence}% |
| Allocation: {allocation}% |
| |
| Reasoning: |
| {reasoning} |
| """ |
| |
| |
| if not analysis_results: |
| return "No analysis results available." |
| |
| latest = analysis_results[-1] |
| |
| timestamp = latest.get("timestamp", datetime.now().isoformat()) |
| signal = latest.get("signal", "unknown").upper() |
| confidence = latest.get("confidence", 0) |
| allocation = latest.get("allocation_percentage", 0) |
| reasoning = latest.get("reasoning", "No reasoning provided.") |
| |
| return f""" |
| **Latest Analysis ({timestamp})** |
| |
| Signal: {signal} |
| Confidence: {confidence}% |
| Allocation: {allocation}% |
| |
| Reasoning: |
| {reasoning} |
| """ |
|
|
| |
| def format_active_positions(): |
| positions = fetch_active_positions() |
| |
| if not positions: |
| return "No active positions." |
| |
| result = "## Active Positions\n\n" |
| |
| for pos in positions: |
| result += f""" |
| **{pos['symbol']}** |
| Quantity: {pos['qty']} BTC |
| Entry: ${pos['avg_entry_price']} |
| Current: ${pos['current_price']} |
| P/L: ${pos['profit_loss']} ({pos['profit_loss_percent']}%) |
| Value: ${pos['market_value']} |
| |
| """ |
| |
| return result |
|
|
| |
| def format_order_history(): |
| |
| db_transactions = get_recent_transactions(10) |
| |
| if db_transactions: |
| result = "## Recent Transactions\n\n" |
| |
| for tx in db_transactions: |
| result += f""" |
| **{tx['symbol']} {tx['action'].upper()}** |
| Quantity: {tx['quantity']} |
| Price: ${tx['price']} |
| Status: {tx['status']} |
| Allocation: {tx['allocation_percentage']}% |
| Date: {tx['timestamp']} |
| Strategy: {tx['strategy_name']} |
| |
| """ |
| |
| return result |
| |
| |
| orders = fetch_order_history() |
| |
| if not orders: |
| return "No order history." |
| |
| result = "## Order History (Last 10)\n\n" |
| |
| for order in orders[:10]: |
| result += f""" |
| **{order['symbol']} {order['side'].upper()}** |
| Quantity: {order['qty']} |
| Type: {order['type']} |
| Status: {order['status']} |
| Created: {order['created_at']} |
| Filled: {order.get('filled_at', 'N/A')} |
| Filled Price: ${order.get('filled_avg_price', 'N/A')} |
| |
| """ |
| |
| return result |
|
|
| |
| def get_available_indicators(): |
| indicators = IndicatorCalculator.get_available_indicators() |
| |
| result = "## Available Indicators\n\n" |
| |
| for name, description in indicators.items(): |
| result += f"**{name}**: {description}\n\n" |
| |
| return result |
|
|
| |
| def format_detailed_analysis_results(result=None): |
| if result is None: |
| |
| db_results = get_recent_analysis_results(1) |
| if db_results: |
| result = db_results[0] |
| elif analysis_results: |
| result = analysis_results[-1] |
| else: |
| return "No analysis results available." |
| |
| |
| timestamp = result.get("timestamp", datetime.now().isoformat()) |
| try: |
| dt = datetime.fromisoformat(timestamp) |
| timestamp = dt.strftime("%Y-%m-%d %H:%M:%S") |
| except (ValueError, TypeError): |
| pass |
| |
| signal = result.get("signal", "unknown").upper() |
| confidence = result.get("confidence", 0) |
| allocation = result.get("allocation_percentage", 0) |
| reasoning = result.get("reasoning", "No reasoning provided.") |
| strategy_name = result.get("strategy_name", "Default Strategy") |
| |
| |
| output = [] |
| output.append("ANALYSIS RESULTS") |
| output.append(f"Timestamp: {timestamp}") |
| output.append("------------------------") |
| output.append(f"Strategy: {strategy_name}") |
| output.append(f"Signal: {signal}") |
| output.append(f"Confidence: {confidence}%") |
| output.append(f"Allocation: {allocation}%") |
| output.append("------------------------") |
| |
| |
| if "technical_indicators" in result and result["technical_indicators"]: |
| output.append("\nTECHNICAL INDICATORS") |
| indicators = result["technical_indicators"] |
| |
| if "price" in indicators: |
| output.append(f"Price: ${indicators['price']:.2f}") |
| |
| rsi_values = [] |
| bb_values = [] |
| macd_values = [] |
| other_values = [] |
| |
| for k, v in indicators.items(): |
| if v is None: |
| continue |
| try: |
| if "rsi" in k.lower(): |
| rsi_values.append(f"{k}: {v:.2f}") |
| elif "bb_" in k.lower(): |
| bb_values.append(f"{k}: {v:.2f}") |
| elif "macd" in k.lower(): |
| macd_values.append(f"{k}: {v:.2f}") |
| elif k != "price": |
| other_values.append(f"{k}: {v:.2f}") |
| except (ValueError, TypeError): |
| if k != "price": |
| other_values.append(f"{k}: {v}") |
| |
| if rsi_values: |
| output.append("\nRSI:") |
| output.extend(rsi_values) |
| |
| if bb_values: |
| output.append("\nBollinger Bands:") |
| output.extend(bb_values) |
| |
| if macd_values: |
| output.append("\nMACD:") |
| output.extend(macd_values) |
| |
| if other_values: |
| output.append("\nOther Indicators:") |
| output.extend(other_values) |
| |
| |
| if "technical_analysis" in result and result["technical_analysis"]: |
| output.append("\n------------------------") |
| output.append("TECHNICAL ANALYSIS") |
| output.append(result["technical_analysis"].strip()) |
| |
| if "initial_analysis" in result and result["initial_analysis"]: |
| output.append("\n------------------------") |
| output.append("MARKET CONTEXT ANALYSIS") |
| output.append(result["initial_analysis"].strip()) |
| |
| if "reflection_analysis" in result and result["reflection_analysis"]: |
| output.append("\n------------------------") |
| output.append("SENTIMENT ANALYSIS") |
| output.append(result["reflection_analysis"].strip()) |
| |
| if reasoning: |
| output.append("\n------------------------") |
| output.append("DETAILED REASONING") |
| output.append(reasoning.strip()) |
| |
| if "market_outlook" in result and result["market_outlook"]: |
| output.append("\n------------------------") |
| output.append("MARKET OUTLOOK") |
| output.append(result["market_outlook"].strip()) |
| |
| if "risk_assessment" in result and result["risk_assessment"]: |
| output.append("\n------------------------") |
| output.append("RISK ASSESSMENT") |
| output.append(result["risk_assessment"].strip()) |
| |
| |
| if ("tool_error_summary" in result and result["tool_error_summary"]) or \ |
| ("tool_error_assessment" in result and result["tool_error_assessment"]): |
| output.append("\n------------------------") |
| output.append("DATA LIMITATIONS") |
| if "tool_error_assessment" in result and result["tool_error_assessment"]: |
| output.append(result["tool_error_assessment"].strip()) |
| if "tool_error_summary" in result and result["tool_error_summary"]: |
| output.append(f"Tool Errors: {result['tool_error_summary']}") |
| |
| |
| if "order_execution" in result and result["order_execution"]: |
| output.append("\n------------------------") |
| output.append("TRADE EXECUTION") |
| if isinstance(result["order_execution"], dict): |
| order = result["order_execution"] |
| output.append("Status: Success") |
| for k, v in order.items(): |
| if k != "success": |
| output.append(f"{k.replace('_', ' ').title()}: {v}") |
| else: |
| output.append(str(result["order_execution"])) |
| |
| |
| return "\n".join(output) |
|
|
| |
| def run_full_analysis_with_check(): |
| try: |
| if not strategy_params.get("strategy_text"): |
| return "Error: No strategy selected. Please load a strategy before running analysis." |
| |
| result = run_full_analysis() |
| if "error" in result: |
| return f"Analysis failed: {result['error']}" |
| |
| return format_detailed_analysis_results(result) |
| except Exception as e: |
| return f"Error running analysis: {str(e)}" |
|
|
| |
| def get_latest_full_analysis(): |
| try: |
| |
| latest_analysis = get_recent_analysis_results(1, full_details=True) |
| |
| if not latest_analysis: |
| |
| if analysis_results: |
| return format_detailed_analysis_results(analysis_results[-1]) |
| else: |
| return "No analysis results available." |
| |
| |
| return format_detailed_analysis_results(latest_analysis) |
| except Exception as e: |
| import traceback |
| return f"Error retrieving latest analysis: {str(e)}\n{traceback.format_exc()}" |
|
|
| |
| def get_analysis_history(): |
| results = get_recent_analysis_results(10) |
| return [ |
| [r["id"], r["timestamp"], r["strategy_name"], r["signal"].upper(), |
| r["confidence"], r["allocation_percentage"]] |
| for r in results |
| ] |
|
|
| |
| def view_detailed_analysis(analysis_id): |
| if analysis_id <= 0: |
| return "Please select a valid analysis result ID" |
| |
| try: |
| conn = sqlite3.connect(DB_PATH) |
| conn.row_factory = sqlite3.Row |
| cursor = conn.cursor() |
| |
| |
| cursor.execute(""" |
| SELECT ar.*, s.name as strategy_name |
| FROM analysis_results ar |
| LEFT JOIN strategies s ON ar.strategy_id = s.id |
| WHERE ar.id = ? |
| """, (int(analysis_id),)) |
| |
| row = cursor.fetchone() |
| conn.close() |
| |
| if not row: |
| return "Analysis result not found" |
| |
| |
| result = dict(row) |
| |
| |
| if "indicator_values" in result and result["indicator_values"]: |
| try: |
| result["technical_indicators"] = json.loads(result["indicator_values"]) |
| except json.JSONDecodeError as e: |
| result["technical_indicators"] = {"error": f"Failed to parse indicators: {str(e)}"} |
| |
| |
| return format_detailed_analysis_results(result) |
| except Exception as e: |
| import traceback |
| return f"Error retrieving analysis details: {str(e)}\n{traceback.format_exc()}" |
|
|
| |
| with gr.Blocks(title="CrypticAI - Bitcoin Trading Dashboard") as app: |
| gr.Markdown("# CrypticAI - Bitcoin Trading Dashboard") |
| |
| with gr.Tabs(): |
| |
| with gr.TabItem("Strategy Configuration"): |
| gr.Markdown("## Strategy Parameters") |
| |
| with gr.Row(): |
| with gr.Column(): |
| timeframe = gr.Slider(minimum=1, maximum=240, value=strategy_params["timeframe_minutes"], step=1, |
| label="Timeframe (minutes)") |
| |
| with gr.Column(): |
| max_allocation = gr.Slider(minimum=5, maximum=100, value=strategy_params["max_allocation_percentage"], step=5, |
| label="Maximum Allocation (%)") |
| |
| strategy_update_btn = gr.Button("Update Strategy Parameters") |
| strategy_message = gr.Textbox(label="Strategy Update Status") |
| |
| strategy_update_btn.click(update_strategy, |
| inputs=[timeframe, max_allocation], |
| outputs=strategy_message) |
| |
| gr.Markdown("---") |
| gr.Markdown("## Strategy Management") |
| |
| |
| with gr.Tabs(): |
| |
| with gr.TabItem("Select Strategy"): |
| gr.Markdown("### Available Strategies") |
| |
| |
| saved_strategies = gr.Dataframe( |
| headers=["ID", "Name", "Description"], |
| datatype=["number", "str", "str"], |
| label="Available Strategies" |
| ) |
| |
| refresh_strategies_btn = gr.Button("Refresh Strategies") |
| |
| def get_strategies_as_df(): |
| strategies = get_saved_strategies() |
| if not strategies: |
| return [[0, "No strategies found", "Create a new strategy first"]] |
| return [[s["id"], s["name"], s["description"]] for s in strategies] |
| |
| refresh_strategies_btn.click(get_strategies_as_df, outputs=saved_strategies) |
| |
| |
| gr.Markdown("### Select a Strategy") |
| |
| def get_strategy_dropdown_choices(): |
| strategies = get_saved_strategies() |
| if not strategies: |
| return [("No strategies available", 0)] |
| return [(f"{s['id']} - {s['name']}", s['id']) for s in strategies] |
| |
| strategy_dropdown = gr.Dropdown( |
| choices=get_strategy_dropdown_choices(), |
| label="Choose Strategy", |
| value=None |
| ) |
| |
| |
| def refresh_all_strategy_displays(): |
| df = get_strategies_as_df() |
| choices = get_strategy_dropdown_choices() |
| return df, choices |
| |
| refresh_strategies_btn.click( |
| refresh_all_strategy_displays, |
| outputs=[saved_strategies, strategy_dropdown] |
| ) |
| |
| |
| with gr.Row(): |
| load_btn = gr.Button("Load Selected Strategy", variant="primary") |
| delete_btn = gr.Button("Delete Selected Strategy", variant="stop") |
| |
| |
| strategy_action_message = gr.Textbox(label="Status", interactive=False) |
| |
| |
| gr.Markdown("### Selected Strategy Details") |
| selected_strategy_view = gr.Markdown("No strategy selected") |
| |
| |
| def load_selected_strategy(strategy_dropdown_value): |
| if not strategy_dropdown_value: |
| return "Please select a strategy first", "No strategy selected" |
| |
| try: |
| strategy_id = int(strategy_dropdown_value) |
| strategy = get_strategy_by_id(strategy_id) |
| |
| if not strategy: |
| return "Strategy not found", "Strategy not found" |
| |
| |
| global strategy_params |
| strategy_params["strategy_text"] = strategy["strategy_text"] |
| for key, value in strategy["parameters"].items(): |
| if key in strategy_params: |
| strategy_params[key] = value |
| |
| |
| view_text = f""" |
| ## {strategy['name']} |
| |
| **Description**: {strategy['description']} |
| |
| **Strategy Logic**: |
| ``` |
| {strategy['strategy_text']} |
| ``` |
| |
| **Parameters**: |
| - Timeframe: {strategy["parameters"].get("timeframe_minutes", "N/A")} minutes |
| - Max Allocation: {strategy["parameters"].get("max_allocation_percentage", "N/A")}% |
| """ |
| |
| |
| return f"Strategy '{strategy['name']}' loaded successfully", view_text |
| except Exception as e: |
| return f"Error loading strategy: {e}", "Error loading strategy" |
| |
| |
| def delete_selected_strategy(strategy_dropdown_value): |
| if not strategy_dropdown_value: |
| return "Please select a strategy first", get_strategy_dropdown_choices() |
| |
| try: |
| strategy_id = int(strategy_dropdown_value) |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| |
| |
| cursor.execute("SELECT name FROM strategies WHERE id = ?", (strategy_id,)) |
| result = cursor.fetchone() |
| |
| if not result: |
| conn.close() |
| return "Strategy not found", get_strategy_dropdown_choices() |
| |
| strategy_name = result[0] |
| |
| |
| cursor.execute("DELETE FROM strategies WHERE id = ?", (strategy_id,)) |
| conn.commit() |
| conn.close() |
| |
| |
| new_choices = get_strategy_dropdown_choices() |
| |
| return f"Strategy '{strategy_name}' deleted successfully", new_choices |
| except Exception as e: |
| return f"Error deleting strategy: {e}", get_strategy_dropdown_choices() |
| |
| |
| load_btn.click( |
| load_selected_strategy, |
| inputs=[strategy_dropdown], |
| outputs=[strategy_action_message, selected_strategy_view] |
| ) |
| |
| delete_btn.click( |
| delete_selected_strategy, |
| inputs=[strategy_dropdown], |
| outputs=[strategy_action_message, strategy_dropdown] |
| ) |
| |
| |
| with gr.TabItem("Create/Edit Strategy"): |
| gr.Markdown("### Strategy Editor") |
| |
| |
| strategy_name = gr.Textbox(label="Strategy Name", placeholder="Enter a name for your strategy") |
| strategy_description = gr.Textbox(label="Strategy Description", placeholder="Enter a brief description of what your strategy does") |
| |
| |
| is_editing = gr.Checkbox(label="Edit Existing Strategy", value=False) |
| edit_id = gr.Number(label="Strategy ID to Edit", value=0, visible=False) |
| |
| |
| edit_strategy_dropdown = gr.Dropdown( |
| choices=get_strategy_dropdown_choices(), |
| label="Choose Strategy to Edit", |
| visible=False |
| ) |
| |
| gr.Markdown("### Strategy Logic") |
| gr.Markdown("""Write your trading strategy using the available indicators. Be specific about entry and exit conditions. |
| |
| **Example Strategy:** |
| ``` |
| Buy when RSI is below 30 and the price is near the lower Bollinger Band (position < 0.2). |
| Sell when RSI is above 70 and the price is near the upper Bollinger Band (position > 0.8). |
| Increase confidence if the ADX shows a strong trend (> 25) in the same direction. |
| Use 40% of available capital for trades if confidence is high (> 70), otherwise use 20%. |
| ``` |
| |
| The strategy will be interpreted by AI to generate trading signals based on current market conditions.""") |
| |
| |
| with gr.Accordion("View Available Indicators", open=False): |
| indicators_info = gr.Markdown(get_available_indicators()) |
| |
| |
| strategy_text = gr.TextArea( |
| label="Strategy Logic", |
| placeholder="Enter your trading strategy logic here...", |
| value=strategy_params.get("strategy_text", ""), |
| lines=10, |
| max_lines=20 |
| ) |
| |
| |
| def toggle_edit_mode(is_editing): |
| return { |
| edit_strategy_dropdown: gr.update(visible=is_editing), |
| } |
| |
| is_editing.change( |
| toggle_edit_mode, |
| inputs=[is_editing], |
| outputs=[edit_strategy_dropdown] |
| ) |
| |
| |
| def load_strategy_to_editor(strategy_dropdown_value): |
| if not strategy_dropdown_value: |
| return "Please select a strategy to edit", "", "", "", 0 |
| |
| try: |
| strategy_id = int(strategy_dropdown_value) |
| strategy = get_strategy_by_id(strategy_id) |
| |
| if not strategy: |
| return "Strategy not found", "", "", "", 0 |
| |
| return "Strategy loaded for editing", strategy["name"], strategy["description"], strategy["strategy_text"], strategy_id |
| except Exception as e: |
| return f"Error loading strategy: {e}", "", "", "", 0 |
| |
| |
| edit_strategy_dropdown.change( |
| load_strategy_to_editor, |
| inputs=[edit_strategy_dropdown], |
| outputs=[strategy_action_message, strategy_name, strategy_description, strategy_text, edit_id] |
| ) |
| |
| |
| save_btn = gr.Button("Save Strategy", variant="primary") |
| save_status = gr.Textbox(label="Save Status", interactive=False) |
| |
| |
| def save_strategy_enhanced(is_editing, edit_id, name, description, text): |
| try: |
| if not name or not text: |
| return "Error: Strategy name and logic are required", get_strategy_dropdown_choices(), get_strategy_dropdown_choices() |
| |
| |
| parameters = strategy_params.copy() |
| parameters["strategy_text"] = text |
| |
| conn = sqlite3.connect(DB_PATH) |
| cursor = conn.cursor() |
| |
| strategy_id = int(edit_id) if is_editing and edit_id > 0 else 0 |
| |
| if is_editing and strategy_id > 0: |
| |
| cursor.execute( |
| "UPDATE strategies SET name = ?, description = ?, strategy_text = ?, parameters = ? WHERE id = ?", |
| (name, description, text, json.dumps(parameters), strategy_id) |
| ) |
| message = f"Strategy '{name}' updated successfully" |
| else: |
| |
| cursor.execute( |
| "INSERT INTO strategies (name, description, strategy_text, parameters) VALUES (?, ?, ?, ?)", |
| (name, description, text, json.dumps(parameters)) |
| ) |
| message = f"Strategy '{name}' saved successfully" |
| |
| conn.commit() |
| conn.close() |
| |
| |
| new_choices = get_strategy_dropdown_choices() |
| |
| return message, new_choices, new_choices |
| except Exception as e: |
| return f"Error saving strategy: {e}", get_strategy_dropdown_choices(), get_strategy_dropdown_choices() |
| |
| |
| save_btn.click( |
| save_strategy_enhanced, |
| inputs=[is_editing, edit_id, strategy_name, strategy_description, strategy_text], |
| outputs=[save_status, strategy_dropdown, edit_strategy_dropdown] |
| ) |
| |
| |
| clear_btn = gr.Button("Clear Form") |
| |
| def clear_form(): |
| return "", "", "", False, 0 |
| |
| clear_btn.click( |
| clear_form, |
| outputs=[strategy_name, strategy_description, strategy_text, is_editing, edit_id] |
| ) |
| |
| gr.Markdown("---") |
| gr.Markdown("## Execute Analysis") |
| gr.Markdown("First select a strategy above, then run the analysis pipeline.") |
| |
| |
| def check_strategy_loaded(): |
| if not strategy_params.get("strategy_text"): |
| return ( |
| "⚠️ No strategy selected! Please load a strategy first.", |
| gr.update(interactive=False) |
| ) |
| else: |
| |
| strategy_text = strategy_params.get("strategy_text", "") |
| |
| |
| strategy_preview = f""" |
| ## Current Strategy |
| |
| ``` |
| {strategy_text} |
| ``` |
| |
| **Parameters**: |
| - Timeframe: {strategy_params.get('timeframe_minutes', 'N/A')} minutes |
| - Max Allocation: {strategy_params.get('max_allocation_percentage', 'N/A')}% |
| """ |
| |
| return ( |
| strategy_preview, |
| gr.update(interactive=True) |
| ) |
| |
| |
| current_strategy_info = gr.Markdown("No strategy loaded") |
| run_pipeline_btn = gr.Button("Run Analysis Pipeline", variant="primary", interactive=False) |
| |
| |
| check_strategy_btn = gr.Button("Check Current Strategy") |
| check_strategy_btn.click( |
| check_strategy_loaded, |
| outputs=[current_strategy_info, run_pipeline_btn] |
| ) |
| |
| |
| analysis_result = gr.TextArea( |
| value="Analysis results will appear here...", |
| label="Analysis Results", |
| lines=25, |
| max_lines=40, |
| interactive=False |
| ) |
| |
| |
| run_pipeline_btn.click( |
| run_full_analysis_with_check, |
| outputs=[analysis_result] |
| ) |
| |
| |
| with gr.TabItem("Trading"): |
| gr.Markdown("## Account Summary") |
| |
| account_summary = gr.Markdown("") |
| |
| with gr.Row(): |
| refresh_account_btn = gr.Button("Refresh Account Info") |
| reset_portfolio_btn = gr.Button("Reset Portfolio") |
| |
| reset_portfolio_message = gr.Textbox(label="Reset Portfolio Status") |
| |
| refresh_account_btn.click(get_account_summary, outputs=account_summary) |
| reset_portfolio_btn.click(reset_portfolio, outputs=reset_portfolio_message) |
| |
| gr.Markdown("## Manual Trading") |
| |
| with gr.Row(): |
| action = gr.Dropdown(["buy", "sell", "check"], label="Action") |
| symbol = gr.Dropdown(["BTC/USD", "ETH/USD"], label="Symbol", value="BTC/USD") |
| allocation = gr.Slider(minimum=1, maximum=100, value=10, label="Allocation Percentage") |
| |
| execute_btn = gr.Button("Execute Trade") |
| trade_result = gr.Textbox(label="Trade Result") |
| |
| execute_btn.click(execute_trade, inputs=[action, symbol, allocation], outputs=trade_result) |
| |
| |
| with gr.TabItem("Monitoring"): |
| with gr.Tabs(): |
| with gr.TabItem("Analysis Results"): |
| gr.Markdown("## Latest Analysis Results") |
| |
| analysis_history = gr.Dataframe( |
| headers=["ID", "Timestamp", "Strategy", "Signal", "Confidence", "Allocation"], |
| datatype=["number", "str", "str", "str", "number", "number"], |
| label="Recent Analysis Results" |
| ) |
| |
| with gr.Row(): |
| refresh_analysis_btn = gr.Button("Refresh Results") |
| view_latest_btn = gr.Button("View Latest Full Analysis", variant="primary") |
| |
| refresh_analysis_btn.click(get_analysis_history, outputs=analysis_history) |
| |
| selected_analysis_id = gr.Number(label="Result ID to View", value=0) |
| view_analysis_btn = gr.Button("View Detailed Analysis") |
| |
| detailed_analysis = gr.TextArea( |
| value="Select an analysis result and click 'View Detailed Analysis'", |
| label="Detailed Analysis Results", |
| lines=25, |
| max_lines=40, |
| interactive=False |
| ) |
| |
| |
| view_latest_btn.click(get_latest_full_analysis, outputs=detailed_analysis) |
| |
| |
| view_analysis_btn.click(view_detailed_analysis, inputs=[selected_analysis_id], outputs=detailed_analysis) |
| |
| with gr.TabItem("Positions"): |
| gr.Markdown("## Active Positions") |
| |
| positions_display = gr.Markdown("") |
| refresh_positions_btn = gr.Button("Refresh Positions") |
| |
| refresh_positions_btn.click(format_active_positions, outputs=positions_display) |
| |
| with gr.TabItem("Transactions"): |
| gr.Markdown("## Transaction History") |
| |
| transactions_history = gr.Dataframe( |
| headers=["ID", "Date", "Symbol", "Action", "Quantity", "Price", "Status"], |
| datatype=["number", "str", "str", "str", "number", "number", "str"], |
| label="Recent Transactions" |
| ) |
| |
| def get_transactions_history(): |
| txs = get_recent_transactions(20) |
| return [ |
| [tx["id"], tx["timestamp"], tx["symbol"], tx["action"].upper(), |
| float(tx["quantity"]), float(tx["price"]), tx["status"]] |
| for tx in txs |
| ] |
| |
| refresh_tx_btn = gr.Button("Refresh Transactions") |
| refresh_tx_btn.click(get_transactions_history, outputs=transactions_history) |
| |
| orders_display = gr.Markdown("") |
| refresh_orders_btn = gr.Button("Show Full Transaction Details") |
| |
| refresh_orders_btn.click(format_order_history, outputs=orders_display) |
| |
| |
| with gr.TabItem("Automated Analysis"): |
| gr.Markdown("## Background Analysis") |
| |
| gr.Markdown(""" |
| ### Full Crew Automated Analysis |
| |
| The automated analysis will run the complete Bitcoin Analysis Crew at intervals defined by the timeframe setting. |
| This includes: |
| - Technical analysis |
| - Market sentiment analysis |
| - Order execution |
| |
| **All trades and analysis results will be logged** to a file in the data directory for later review. |
| """) |
| |
| gr.Markdown(f"Current timeframe: **{strategy_params['timeframe_minutes']} minutes**") |
| |
| with gr.Row(): |
| start_btn = gr.Button("Start Automated Analysis", variant="primary") |
| stop_btn = gr.Button("Stop Automated Analysis", variant="stop") |
| |
| auto_status = gr.Textbox(label="Automation Status") |
| |
| start_btn.click(start_background_process, outputs=auto_status) |
| stop_btn.click(stop_background_process, outputs=auto_status) |
| |
| |
| log_path_info = gr.Markdown(f""" |
| **Log File Location** |
| |
| Trading logs will be saved to: |
| ``` |
| {os.path.dirname(DB_PATH)} |
| ``` |
| A new log file is created for each trading session with format: `auto_trading_log_YYYYMMDD_HHMMSS.txt` |
| |
| These logs contain: |
| - All analysis results |
| - Trade executions |
| - Account balances |
| - Profit/loss tracking |
| - Errors and warnings |
| """) |
| |
| auto_result = gr.TextArea( |
| value="Automated analysis results will appear here...", |
| label="Automated Analysis Results", |
| lines=25, |
| max_lines=40, |
| interactive=False |
| ) |
| |
| |
| auto_refresh = gr.Button("Refresh Latest Results") |
| |
| |
| auto_refresh.click(get_latest_full_analysis, outputs=auto_result) |
| |
| |
| gr.Markdown(""" |
| **IMPORTANT**: Make sure you have loaded a strategy from the Strategy Configuration tab before starting automated analysis. |
| The system will use the currently loaded strategy for all automated runs. |
| """) |
| |
| |
| gr.Markdown(""" |
| ### Running for Extended Periods |
| |
| To run this application continuously for days: |
| |
| 1. Start the automated analysis with your chosen strategy and timeframe |
| 2. Keep this application running (do not close the browser tab or terminal) |
| 3. If running on a remote server, use tools like `screen` or `tmux` to keep the session alive |
| |
| **Example terminal command for persistent session**: |
| ``` |
| # Start a new screen session |
| screen -S cryptic_trading |
| |
| # Then run your application in that session |
| python src/ui/app.py |
| |
| # You can detach from the session with Ctrl+A, D and reconnect later with: |
| screen -r cryptic_trading |
| ``` |
| """) |
|
|
| |
| if __name__ == "__main__": |
| |
| os.makedirs("results", exist_ok=True) |
| |
| |
| fetch_account_info() |
| fetch_order_history() |
| fetch_active_positions() |
| |
| |
| app.launch() |