{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# GRU-SAC Trading Pipeline: Step-by-Step Walkthrough\n", "\n", "This notebook demonstrates how to instantiate and run the refactored `TradingPipeline` class **sequentially**, executing each major step individually.\n", "\n", "**Goal:** Run the complete pipeline (data loading, feature engineering, GRU training/loading, calibration, SAC loading, backtesting) using a configuration file, inspecting the inputs and outputs at each stage." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Imports and Setup\n", "\n", "Import necessary libraries and configure path variables to locate the project code." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Initial sys.path: ['/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '', '/home/yasha/develop/gru_sac_predictor/.venv/lib/python3.10/site-packages']\n", "Notebook directory (notebook_dir): /home/yasha/develop/gru_sac_predictor/gru_sac_predictor/notebooks\n", "Calculated path for imports (package_root_for_imports): /home/yasha/develop/gru_sac_predictor/gru_sac_predictor\n", "Checking if /home/yasha/develop/gru_sac_predictor/gru_sac_predictor is in sys.path...\n", "Path not found. Adding /home/yasha/develop/gru_sac_predictor/gru_sac_predictor to sys.path.\n", "sys.path after insert: ['/home/yasha/develop/gru_sac_predictor/gru_sac_predictor', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '', '/home/yasha/develop/gru_sac_predictor/.venv/lib/python3.10/site-packages']\n", "Project root for config/data (project_root): /home/yasha/develop/gru_sac_predictor\n", "Attempting to import TradingPipeline...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2025-04-18 03:17:10.421895: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", "E0000 00:00:1744946230.439676 157301 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", "E0000 00:00:1744946230.445571 157301 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", "/home/yasha/develop/gru_sac_predictor/.venv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", " from .autonotebook import tqdm as notebook_tqdm\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Successfully imported TradingPipeline.\n" ] } ], "source": [ "import os\n", "import sys\n", "import yaml\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import matplotlib.image as mpimg\n", "import logging\n", "\n", "print(f'Initial sys.path: {sys.path}')\n", "\n", "# --- Path Setup ---\n", "# Initialize project_root to None\n", "project_root = None\n", "package_root_for_imports = None # Initialize separately for clarity\n", "try:\n", " notebook_dir = os.path.abspath('') # Get current directory (should be notebooks/)\n", " print(f'Notebook directory (notebook_dir): {notebook_dir}')\n", "\n", " # Go up ONE level to get the package root directory\n", " # Since notebook is in .../gru_sac_predictor/notebooks/, parent is .../gru_sac_predictor/\n", " package_root_for_imports = os.path.dirname(notebook_dir)\n", " print(f'Calculated path for imports (package_root_for_imports): {package_root_for_imports}')\n", "\n", " # Add the calculated path to sys.path to allow imports\n", " print(f'Checking if {package_root_for_imports} is in sys.path...')\n", " if package_root_for_imports not in sys.path:\n", " print(f'Path not found. Adding {package_root_for_imports} to sys.path.')\n", " sys.path.insert(0, package_root_for_imports)\n", " print(f'sys.path after insert: {sys.path}')\n", " else:\n", " print(f'Path {package_root_for_imports} already in sys.path.')\n", "\n", " # Define project_root consistently, used later for finding config.yaml\n", " # It should be the *outer* directory containing the package and config\n", " project_root = os.path.dirname(package_root_for_imports) # Go up one more level\n", " print(f'Project root for config/data (project_root): {project_root}')\n", "\n", "except Exception as e:\n", " print(f'Error during path setup: {e}')\n", "\n", "# --- Import the main pipeline class ---\n", "print(\"Attempting to import TradingPipeline...\")\n", "try:\n", " # Import relative to the package root added to sys.path\n", " from src.trading_pipeline import TradingPipeline\n", " print('Successfully imported TradingPipeline.')\n", "except ImportError as e:\n", " print(f'ERROR: Failed to import TradingPipeline: {e}')\n", " print(f'Final sys.path before error: {sys.path}')\n", " print(\"Please verify the project structure and the paths added to sys.path.\")\n", "except Exception as e: # Catch other potential errors\n", " print(f'An unexpected error occurred during import: {e}')\n", " print(f'Final sys.path before error: {sys.path}')\n", "\n", "# Configure basic logging for the notebook\n", "logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n", "\n", "# Set pandas display options for better inspection\n", "pd.set_option('display.max_columns', None) # Show all columns\n", "pd.set_option('display.max_rows', 100) # Show more rows if needed\n", "pd.set_option('display.width', 1000) # Wider display" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Configuration\n", "\n", "Specify the path to the configuration file (`config.yaml`). This file defines all parameters for the data, models, training, and backtesting." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using config file: /home/yasha/develop/gru_sac_predictor/gru_sac_predictor/config.yaml\n", "Config file found.\n" ] } ], "source": [ "# Path to the configuration file\n", "# Assumes config.yaml is in the directory *above* the package root\n", "config_rel_path = 'gru_sac_predictor/config.yaml' # Relative to project_root defined above\n", "config_abs_path = None\n", "\n", "# Construct absolute path relative to the project root identified earlier\n", "if 'project_root' in locals() and project_root: # Check if project_root was successfully determined\n", " config_abs_path = os.path.join(project_root, config_rel_path)\n", "else:\n", " print('ERROR: project_root not defined. Cannot find config file.')\n", "\n", "if config_abs_path:\n", " print(f'Using config file: {config_abs_path}')\n", " # Verify the config file exists\n", " if not os.path.exists(config_abs_path):\n", " print(f'ERROR: Config file not found at {config_abs_path}')\n", " else:\n", " print('Config file found.')\n", " # Optionally load and display config for verification\n", " try:\n", " with open(config_abs_path, 'r') as f:\n", " config_data = yaml.safe_load(f)\n", " # print('\\nConfiguration:')\n", " # print(yaml.dump(config_data, default_flow_style=False)) # Pretty print\n", " except Exception as e:\n", " print(f'Error reading config file: {e}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Instantiate the Pipeline\n", "\n", "Create an instance of the `TradingPipeline` class, passing the path to the configuration file. This initializes the pipeline object but does not run any steps yet." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Instantiating TradingPipeline...\n", "2025-04-18 03:17:13,554 - root - INFO - Using Base Models Directory: /home/yasha/develop/gru_sac_predictor/models\n", "2025-04-18 03:17:13,555 - root - INFO - Using results directory: /home/yasha/develop/gru_sac_predictor/results/20250418_031713\n", "2025-04-18 03:17:13,555 - root - INFO - Using logs directory: /home/yasha/develop/gru_sac_predictor/logs/20250418_031713\n", "2025-04-18 03:17:13,556 - root - INFO - Using models directory: /home/yasha/develop/gru_sac_predictor/models/20250418_031713\n", "2025-04-18 03:17:13,557 - root - INFO - Logging setup complete. Log file: /home/yasha/develop/gru_sac_predictor/logs/20250418_031713/pipeline_20250418_031713.log\n", "2025-04-18 03:17:13,558 - root - INFO - --- Starting Pipeline Run: 20250418_031713 ---\n", "2025-04-18 03:17:13,559 - root - INFO - Using config: /home/yasha/develop/gru_sac_predictor/gru_sac_predictor/config.yaml\n", "2025-04-18 03:17:13,560 - root - INFO - Resolved relative db_dir '../../data/crypto_market_data' to absolute path: /home/yasha/data/crypto_market_data\n", "2025-04-18 03:17:13,561 - gru_sac_predictor.src.data_loader - INFO - Initialized DataLoader with db_dir='/home/yasha/data/crypto_market_data'\n", "2025-04-18 03:17:13,562 - gru_sac_predictor.src.data_loader - WARNING - Database directory does not exist: /home/yasha/data/crypto_market_data\n", "2025-04-18 03:17:13,563 - gru_sac_predictor.src.feature_engineer - INFO - FeatureEngineer initialized with minimal whitelist: ['return_1m', 'return_15m', 'return_60m', 'ATR_14', 'volatility_14d', 'chaikin_AD_10', 'svi_10', 'EMA_10', 'EMA_50', 'MACD', 'MACD_signal', 'hour_sin', 'hour_cos']\n", "2025-04-18 03:17:13,564 - gru_sac_predictor.src.gru_model_handler - INFO - GRUModelHandler initialized for run 20250418_031713 in /home/yasha/develop/gru_sac_predictor/models/20250418_031713\n", "2025-04-18 03:17:13,564 - gru_sac_predictor.src.calibrator - INFO - Calibrator initialized with edge threshold: 0.55\n", "2025-04-18 03:17:13,565 - gru_sac_predictor.src.backtester - INFO - Backtester initialized.\n", "2025-04-18 03:17:13,566 - gru_sac_predictor.src.backtester - INFO - Initial Capital: 10000.00\n", "2025-04-18 03:17:13,566 - gru_sac_predictor.src.backtester - INFO - Transaction Cost: 0.0500%\n", "2025-04-18 03:17:13,567 - gru_sac_predictor.src.backtester - INFO - Edge Threshold: 0.550\n", "2025-04-18 03:17:13,575 - root - INFO - Saved run configuration to /home/yasha/develop/gru_sac_predictor/results/20250418_031713/run_config.yaml\n", "TradingPipeline instantiated successfully.\n", "Run ID: 20250418_031713\n", "Results Dir: /home/yasha/develop/gru_sac_predictor/results/20250418_031713\n", "Log Dir: /home/yasha/develop/gru_sac_predictor/logs/20250418_031713\n", "Models Dir: /home/yasha/develop/gru_sac_predictor/models/20250418_031713\n" ] } ], "source": [ "pipeline_instance = None # Define outside try block\n", "if 'TradingPipeline' in locals() and config_abs_path and os.path.exists(config_abs_path):\n", " try:\n", " # Instantiate the pipeline\n", " print('Instantiating TradingPipeline...')\n", " pipeline_instance = TradingPipeline(config_path=config_abs_path)\n", " print('TradingPipeline instantiated successfully.')\n", " print(f'Run ID: {pipeline_instance.run_id}')\n", " print(f'Results Dir: {pipeline_instance.dirs[\"results\"]}')\n", " print(f'Log Dir: {pipeline_instance.dirs[\"logs\"]}')\n", " print(f'Models Dir: {pipeline_instance.dirs[\"models\"]}')\n", "\n", " except FileNotFoundError as e:\n", " print(f'ERROR during pipeline instantiation (FileNotFound): {e}')\n", " except Exception as e:\n", " print(f'An error occurred during pipeline instantiation: {e}')\n", " logging.error('Pipeline instantiation failed.', exc_info=True) # Log traceback\n", "else:\n", " print('TradingPipeline class not imported, config path invalid, or config file not found. Cannot instantiate pipeline.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. Step 1: Load Data\n", "\n", "Call the `load_data` method to fetch the raw market data based on the configuration." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "=== Running Step 1: Load Data ===\n", "2025-04-18 03:17:15,747 - root - INFO - --- Notebook Step: Load Data (Calling load_and_preprocess_data) ---\n", "2025-04-18 03:17:15,749 - root - INFO - --- Stage: Loading and Preprocessing Data ---\n", "2025-04-18 03:17:15,751 - gru_sac_predictor.src.data_loader - INFO - Loading data for SOL-USDT (bnbspot) from 2024-06-01 to 2025-03-10, interval 1min\n", "2025-04-18 03:17:15,767 - gru_sac_predictor.src.data_loader - INFO - Scanning for DB files recursively in: /home/yasha/data/crypto_market_data\n", "2025-04-18 03:17:15,769 - gru_sac_predictor.src.data_loader - ERROR - Database directory /home/yasha/data/crypto_market_data does not exist\n", "2025-04-18 03:17:15,773 - gru_sac_predictor.src.data_loader - ERROR - No relevant DB files found and no fallback files available.\n", "2025-04-18 03:17:15,774 - gru_sac_predictor.src.data_loader - ERROR - No relevant database files found for the specified date range.\n", "2025-04-18 03:17:15,779 - root - ERROR - Failed to load data. Exiting.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "No traceback available to show.\n" ] }, { "ename": "SystemExit", "evalue": "1", "output_type": "error", "traceback": [ "An exception has occurred, use %tb to see the full traceback.\n", "\u001b[0;31mSystemExit\u001b[0m\u001b[0;31m:\u001b[0m 1\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/yasha/develop/gru_sac_predictor/.venv/lib/python3.10/site-packages/IPython/core/interactiveshell.py:3587: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n", " warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n" ] } ], "source": [ "%tb\n", "if pipeline_instance:\n", " try:\n", " print('\\n=== Running Step 1: Load Data ===')\n", " pipeline_instance.load_data()\n", " print('load_data() finished.')\n", "\n", " print('\\n--- Inspecting Raw Data ---')\n", " if pipeline_instance.raw_data is not None:\n", " print(f'Shape of raw_data: {pipeline_instance.raw_data.shape}')\n", " display(pipeline_instance.raw_data.head())\n", " display(pipeline_instance.raw_data.tail())\n", " display(pipeline_instance.raw_data.isnull().sum()) # Check for NaNs\n", " else:\n", " print('raw_data attribute is None.')\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Load Data step: {e}')\n", " logging.error('Load Data step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated. Cannot run step.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5. Step 2: Engineer Features\n", "\n", "Call the `engineer_features` method to create technical indicators and other features from the raw data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if pipeline_instance and pipeline_instance.raw_data is not None:\n", " try:\n", " print('\\n=== Running Step 2: Engineer Features ===')\n", " pipeline_instance.engineer_features()\n", " print('engineer_features() finished.')\n", "\n", " print('\\n--- Inspecting Features DataFrame ---')\n", " if pipeline_instance.features_df is not None:\n", " print(f'Shape of features_df: {pipeline_instance.features_df.shape}')\n", " display(pipeline_instance.features_df.head())\n", " display(pipeline_instance.features_df.tail())\n", " display(pipeline_instance.features_df.isnull().sum()) # Check for NaNs introduced by features\n", " else:\n", " print('features_df attribute is None.')\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Engineer Features step: {e}')\n", " logging.error('Engineer Features step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated or raw_data missing. Cannot run step.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6. Step 3: Prepare Sequences\n", "\n", "Call the `prepare_sequences` method to split the data into train/validation/test sets and create sequences suitable for the GRU model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if pipeline_instance and pipeline_instance.features_df is not None:\n", " try:\n", " print('\\n=== Running Step 3: Prepare Sequences ===')\n", " pipeline_instance.prepare_sequences()\n", " print('prepare_sequences() finished.')\n", "\n", " print('\\n--- Inspecting Sequences and Targets ---')\n", " # Assuming attributes like train_sequences, val_targets etc. exist\n", " for name in ['train_sequences', 'val_sequences', 'test_sequences',\n", " 'train_targets', 'val_targets', 'test_targets',\n", " 'train_indices', 'val_indices', 'test_indices']:\n", " attr = getattr(pipeline_instance, name, None)\n", " if attr is not None:\n", " # Check if it's numpy array or pandas series/df before getting shape\n", " if hasattr(attr, 'shape'):\n", " print(f'{name} shape: {attr.shape}')\n", " else:\n", " print(f'{name} type: {type(attr)}, length: {len(attr)}') # For lists like indices\n", " else:\n", " print(f'{name} attribute is None.')\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Prepare Sequences step: {e}')\n", " logging.error('Prepare Sequences step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated or features_df missing. Cannot run step.')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7. Step 4: Train or Load GRU Model\n", "\n", "Call `train_or_load_gru` to either train a new GRU model or load a pre-trained one, based on the configuration flags." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if pipeline_instance and pipeline_instance.train_sequences is not None: # Check if sequences are ready\n", " try:\n", " print('\\n=== Running Step 4: Train or Load GRU ===')\n", " pipeline_instance.train_or_load_gru()\n", " print('train_or_load_gru() finished.')\n", "\n", " print('\\n--- Inspecting GRU Handler ---')\n", " if pipeline_instance.gru_handler is not None:\n", " print(f'GRU Handler instantiated: {pipeline_instance.gru_handler}')\n", " # Potentially inspect model summary if handler exposes it\n", " # print(pipeline_instance.gru_handler.model.summary())\n", " print(f'GRU Predictions available (val): {hasattr(pipeline_instance.gru_handler, \"val_predictions\")}')\n", " print(f'GRU Predictions available (test): {hasattr(pipeline_instance.gru_handler, \"test_predictions\")}')\n", " else:\n", " print('gru_handler attribute is None.')\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Train/Load GRU step: {e}')\n", " logging.error('Train/Load GRU step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated or sequences missing. Cannot run step.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 8. Step 5: Calibrate Predictions\n", "\n", "Call `calibrate_predictions` to use the validation set predictions from the GRU to find an optimal probability threshold or apply other calibration techniques." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if pipeline_instance and pipeline_instance.gru_handler is not None and hasattr(pipeline_instance.gru_handler, 'val_predictions'):\n", " try:\n", " print('\\n=== Running Step 5: Calibrate Predictions ===')\n", " pipeline_instance.calibrate_predictions()\n", " print('calibrate_predictions() finished.')\n", "\n", " print('\\n--- Inspecting Calibration Results ---')\n", " if pipeline_instance.calibrator is not None:\n", " print(f'Calibrator object: {pipeline_instance.calibrator}')\n", " print(f'Optimal threshold: {getattr(pipeline_instance, \"optimal_threshold\", \"Not set\")}')\n", " print(f'Calibrated Val Probs exist: {hasattr(pipeline_instance.calibrator, \"calibrated_val_probabilities\")}')\n", " print(f'Calibrated Test Probs exist: {hasattr(pipeline_instance.calibrator, \"calibrated_test_probabilities\")}')\n", "\n", " else:\n", " print('calibrator attribute is None.')\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Calibrate Predictions step: {e}')\n", " logging.error('Calibrate Predictions step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated or GRU validation predictions missing. Cannot run step.')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 9. Step 6: Prepare SAC Agent for Backtest\n", "\n", "Call `train_or_load_sac`. This step might involve triggering offline SAC training (if configured) or simply identifying and setting the path to the pre-trained SAC agent policy to be used in the backtest." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Note: Actual SAC training might be complex to run directly inline.\n", "# This step often just prepares the necessary info (like the agent path) for the backtester.\n", "if pipeline_instance:\n", " try:\n", " print('\\n=== Running Step 6: Train or Load SAC (Prepare for Backtest) ===')\n", " # This might just set an attribute like sac_agent_path based on config\n", " pipeline_instance.train_or_load_sac()\n", " print('train_or_load_sac() finished.')\n", "\n", " print('\\n--- Inspecting SAC Agent Info ---')\n", " # Check the attribute storing the path or relevant SAC info\n", " print(f'SAC Agent Path for backtest: {getattr(pipeline_instance, \"sac_agent_path\", \"Not set\")}')\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Train/Load SAC step: {e}')\n", " logging.error('Train/Load SAC step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated. Cannot run step.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 10. Step 7: Run Backtest\n", "\n", "Execute the trading simulation using the test data, GRU predictions (calibrated), and the loaded SAC agent policy." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Check if necessary components are ready\n", "backtest_ready = (\n", " pipeline_instance and\n", " pipeline_instance.test_sequences is not None and\n", " pipeline_instance.test_targets is not None and\n", " pipeline_instance.test_indices is not None and\n", " pipeline_instance.gru_handler is not None and\n", " pipeline_instance.calibrator is not None and # Ensure calibration ran\n", " getattr(pipeline_instance, \"optimal_threshold\", None) is not None and\n", " getattr(pipeline_instance, \"sac_agent_path\", None) is not None\n", ")\n", "\n", "if backtest_ready:\n", " try:\n", " print('\\n=== Running Step 7: Run Backtest ===')\n", " pipeline_instance.run_backtest()\n", " print('run_backtest() finished.')\n", "\n", " print('\\n--- Inspecting Backtest Results ---')\n", " if pipeline_instance.backtest_metrics:\n", " print('\\n--- Backtest Metrics --- ')\n", " metrics = pipeline_instance.backtest_metrics\n", " metrics['Run ID'] = pipeline_instance.run_id # Add run ID for context\n", " for key, value in metrics.items():\n", " if key == \"Confusion Matrix (GRU Signal vs Actual Dir)\":\n", " print(f'{key}:\\\\n{np.array(value)}')\n", " elif key == \"Classification Report (GRU Signal)\":\n", " print(f'{key}:\\\\n{value}')\n", " elif isinstance(value, float):\n", " print(f'{key}: {value:.4f}')\n", " else:\n", " print(f'{key}: {value}')\n", " else:\n", " print('Backtest metrics not available.')\n", "\n", " if pipeline_instance.backtest_results_df is not None:\n", " print('\\n--- Backtest Results DataFrame (Head) --- ')\n", " display(pipeline_instance.backtest_results_df.head())\n", " print('\\n--- Backtest Results DataFrame (Tail) --- ')\n", " display(pipeline_instance.backtest_results_df.tail())\n", " print('\\n--- Backtest Results DataFrame (Description) --- ')\n", " display(pipeline_instance.backtest_results_df.describe())\n", " else:\n", " print('Backtest results DataFrame not available.')\n", "\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Run Backtest step: {e}')\n", " logging.error('Run Backtest step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated or prerequisites for backtest are missing. Cannot run step.')\n", " print(f\"Prerequisites check: pipeline={bool(pipeline_instance)}, test_sequences={pipeline_instance.test_sequences is not None if pipeline_instance else False}, \"\n", " f\"test_targets={pipeline_instance.test_targets is not None if pipeline_instance else False}, test_indices={pipeline_instance.test_indices is not None if pipeline_instance else False}, \"\n", " f\"gru_handler={pipeline_instance.gru_handler is not None if pipeline_instance else False}, calibrator={pipeline_instance.calibrator is not None if pipeline_instance else False}, \"\n", " f\"optimal_T={getattr(pipeline_instance, 'optimal_threshold', None) is not None}, sac_path={getattr(pipeline_instance, 'sac_agent_path', None) is not None}\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 11. Step 8: Save Results\n", "\n", "Save the calculated metrics, the detailed backtest results DataFrame, and any generated plots to the run-specific output directory." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if pipeline_instance and pipeline_instance.backtest_results_df is not None and pipeline_instance.backtest_metrics:\n", " try:\n", " print('\\n=== Running Step 8: Save Results ===')\n", " pipeline_instance.save_results()\n", " print('save_results() finished.')\n", " print(f'Results should be saved in: {pipeline_instance.dirs[\"results\"]}')\n", "\n", " except Exception as e:\n", " print(f'An error occurred during Save Results step: {e}')\n", " logging.error('Save Results step failed.', exc_info=True)\n", "else:\n", " print('Pipeline not instantiated or backtest results/metrics missing. Cannot run step.')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 12. Display Saved Plots\n", "\n", "Load and display the plots generated and saved during the pipeline execution (especially during calibration and backtesting/saving)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# This code assumes plots were generated and saved by previous steps (like calibrate or save_results)\n", "if pipeline_instance is not None and pipeline_instance.dirs.get('results'):\n", " results_dir = pipeline_instance.dirs['results']\n", " run_id = pipeline_instance.run_id\n", " print(f'\\nLooking for plots in: {results_dir}\\n')\n", "\n", " plot_files = [\n", " f'backtest_summary_{run_id}.png',\n", " f'confusion_matrix_{run_id}.png',\n", " f'reliability_curve_val_{run_id}.png', # Generated by calibration\n", " f'calibration_curve_test_{run_id}.png' # Potentially generated by backtester/save_results\n", " # Add any other plot filenames generated by your pipeline\n", " ]\n", "\n", " plot_found = False\n", " for plot_file in plot_files:\n", " plot_path = os.path.join(results_dir, plot_file)\n", " if os.path.exists(plot_path):\n", " plot_found = True\n", " print(f'--- Displaying: {plot_file} ---')\n", " try:\n", " img = mpimg.imread(plot_path)\n", " # Determine appropriate figure size based on plot type\n", " figsize = (15, 12) if 'summary' in plot_file else (8, 7)\n", " plt.figure(figsize=figsize)\n", " plt.imshow(img)\n", " plt.axis('off') # Hide axes for image display\n", " plt.title(plot_file)\n", " plt.show()\n", " except Exception as e:\n", " print(f' Error loading/displaying plot {plot_file}: {e}')\n", " else:\n", " print(f'Plot not found: {plot_path}')\n", "\n", " if not plot_found:\n", " print(\"No standard plots found in the results directory.\")\n", "\n", "else:\n", " print('\\nPipeline object not found or results directory is not available. Cannot display plots.')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 13. Conclusion\n", "\n", "This notebook demonstrated the step-by-step workflow of using the `TradingPipeline`. By running each step individually, we could inspect the intermediate outputs. You can modify the `config.yaml` file to experiment with different parameters, data ranges, and control flags, then re-run the relevant steps of this notebook. The final results (metrics, plots, detailed CSV) are saved in the run-specific directory under the main project's `results/` folder." ] } ], "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.10.12" } }, "nbformat": 4, "nbformat_minor": 4 }