0cf37e786a
- Add detailed README with architecture diagram and usage instructions - Add API, configuration, and development documentation - Fix price data column handling for yfinance auto_adjust=True - Fix model feature dimension indexing and temporal attention batching - Add missing imports and position tracking in paper broker - Add python-dotenv support for environment variables - Update .gitignore with Python artifacts and environment files
157 lines
5.0 KiB
Python
157 lines
5.0 KiB
Python
import logging
|
|
from datetime import datetime
|
|
|
|
import matplotlib.pyplot as plt
|
|
import pandas as pd
|
|
from src.evaluation.backtester import GNNBacktester
|
|
from src.evaluation.metrics import calculate_performance_metrics, compare_to_benchmark
|
|
from src.utils.visualization import (
|
|
plot_feature_importance,
|
|
plot_performance,
|
|
plot_trade_log,
|
|
)
|
|
|
|
from config import config
|
|
from src.amd.optimizations import AMDOptimizer
|
|
from src.data.pipeline import StockDataPipeline
|
|
from src.models.gnn_model import CorporateActionAwareGNN
|
|
from src.models.trainer import GNNTrainer
|
|
from src.utils.memory_manager import MemoryManager
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
handlers=[
|
|
logging.FileHandler("stock_gnn_r9700.log"),
|
|
logging.StreamHandler(),
|
|
],
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def main():
|
|
# Initialize memory manager
|
|
memory_manager = MemoryManager()
|
|
logger.info(memory_manager.get_memory_stats())
|
|
|
|
# Initialize AMD optimizer
|
|
amd_optimizer = AMDOptimizer()
|
|
|
|
# Initialize data pipeline
|
|
logger.info("Initializing data pipeline")
|
|
pipeline = StockDataPipeline()
|
|
|
|
# Update all data
|
|
logger.info("Updating all data sources")
|
|
pipeline.update_all_data()
|
|
|
|
# Create datasets
|
|
logger.info("Creating training and validation datasets")
|
|
train_dataset = pipeline.create_training_dataset()
|
|
val_dataset = pipeline.create_validation_dataset(
|
|
start_date=config.TRAIN_END_DATE, end_date=config.VAL_END_DATE
|
|
)
|
|
|
|
logger.info(f"Training dataset size: {len(train_dataset)}")
|
|
logger.info(f"Validation dataset size: {len(val_dataset)}")
|
|
|
|
# Initialize model
|
|
logger.info("Initializing GNN model")
|
|
# x has shape (num_stocks, seq_len, num_features); features are in the last dim
|
|
num_features = train_dataset[0].x.shape[2]
|
|
model = CorporateActionAwareGNN(num_features)
|
|
|
|
# Optimize model for AMD GPU
|
|
model = amd_optimizer.optimize_model(model)
|
|
|
|
# Train model
|
|
logger.info("Training model with AMD optimizations")
|
|
trainer = GNNTrainer(model)
|
|
train_losses, val_losses = trainer.train(train_dataset, val_dataset)
|
|
|
|
# Plot training curves
|
|
plt.figure(figsize=(10, 5))
|
|
plt.plot(train_losses, label="Training Loss")
|
|
plt.plot(val_losses, label="Validation Loss")
|
|
plt.title("Training and Validation Loss")
|
|
plt.xlabel("Epoch")
|
|
plt.ylabel("Loss")
|
|
plt.legend()
|
|
plt.savefig("training_curves.png")
|
|
plt.close()
|
|
|
|
# Benchmark model
|
|
logger.info("Benchmarking model performance")
|
|
sample_data = train_dataset[0].to(config.DEVICE)
|
|
benchmark_results = trainer.benchmark(sample_data)
|
|
logger.info(f"Benchmark Results: {benchmark_results}")
|
|
|
|
# Load best model
|
|
trainer.load_model()
|
|
|
|
# Run backtest on validation set
|
|
logger.info("Running backtest on validation set")
|
|
backtester = GNNBacktester(model, pipeline)
|
|
portfolio_values, trade_log = backtester.run_backtest(val_dataset)
|
|
|
|
# Get benchmark data (auto_adjust=True means 'Close' already contains adjusted prices)
|
|
benchmark_data = pipeline.price_data[config.INDEX_TICKER]
|
|
benchmark_values = benchmark_data.loc[portfolio_values.index]["Close"]
|
|
|
|
# Calculate performance metrics
|
|
logger.info("Calculating performance metrics")
|
|
portfolio_returns = portfolio_values.pct_change().dropna()
|
|
benchmark_returns = benchmark_values.pct_change().dropna()
|
|
|
|
metrics = calculate_performance_metrics(portfolio_returns, benchmark_returns)
|
|
comparison = compare_to_benchmark(portfolio_values, benchmark_values)
|
|
|
|
# Print metrics
|
|
logger.info("\nPerformance Metrics:")
|
|
for metric, value in metrics.items():
|
|
if isinstance(value, float):
|
|
logger.info(f"{metric.replace('_', ' ').title()}: {value:.4f}")
|
|
else:
|
|
logger.info(f"{metric.replace('_', ' ').title()}: {value}")
|
|
|
|
logger.info("\nComparison to Benchmark:")
|
|
for metric, value in comparison.items():
|
|
if isinstance(value, float):
|
|
logger.info(f"{metric.replace('_', ' ').title()}: {value:.4f}")
|
|
else:
|
|
logger.info(f"{metric.replace('_', ' ').title()}: {value}")
|
|
|
|
# Plot performance
|
|
plot_performance(portfolio_values, benchmark_values, "portfolio_performance.png")
|
|
|
|
# Plot trade log
|
|
plot_trade_log(trade_log, "trade_log.png")
|
|
|
|
# Save results
|
|
results = {
|
|
"portfolio_values": portfolio_values,
|
|
"benchmark_values": benchmark_values,
|
|
"trade_log": trade_log,
|
|
"metrics": metrics,
|
|
"comparison": comparison,
|
|
}
|
|
|
|
results_df = pd.DataFrame(
|
|
{
|
|
"date": portfolio_values.index,
|
|
"portfolio_value": portfolio_values.values,
|
|
"benchmark_value": benchmark_values.values,
|
|
}
|
|
)
|
|
results_df.to_csv("backtest_results.csv", index=False)
|
|
|
|
# Memory cleanup
|
|
memory_manager.empty_cache()
|
|
logger.info("Backtest completed. Results saved to backtest_results.csv")
|
|
logger.info(memory_manager.get_memory_stats())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|