feat: add PDF report generation for backtest executions
- Implemented `generate_backtest_report` to create PDF reports for backtest results. - Added `report_file` field to `StrategyExecution` for storing report paths. - Introduced `/executions/<execution_id>/report/` endpoint for downloading reports. - Enhanced backtesting flow to generate and save reports upon completion. - Updated dependencies to include `matplotlib` for report generation.
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.http import FileResponse, JsonResponse
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.http import JsonResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.utils import timezone
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
import requests
|
||||
import logging
|
||||
|
||||
from .models import QuantStrategy, StrategyVersion, StrategyExecution
|
||||
from .base import StrategyRegistry
|
||||
from .services.backtest import run_backtest
|
||||
from .services.report import generate_backtest_report
|
||||
from . import implementations # 구현체들을 로드하여 레지스트리에 등록
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -218,6 +222,9 @@ def execution_status(request, execution_id):
|
||||
if execution.status == 'completed' and execution.result:
|
||||
response_data['result'] = execution.result
|
||||
|
||||
if execution.report_file:
|
||||
response_data['report_url'] = f'/api/executions/{execution.id}/report/'
|
||||
|
||||
if execution.status == 'failed' and execution.error_message:
|
||||
response_data['error_message'] = execution.error_message
|
||||
|
||||
@@ -312,6 +319,13 @@ def backtest_strategy(request):
|
||||
execution.status = 'completed'
|
||||
execution.result = result
|
||||
execution.completed_at = timezone.now()
|
||||
|
||||
try:
|
||||
report_path = generate_backtest_report(result, execution.id)
|
||||
execution.report_file = report_path
|
||||
except Exception as report_err:
|
||||
logger.exception(f'PDF report generation failed for execution {execution.id}: {report_err}')
|
||||
|
||||
execution.save()
|
||||
|
||||
except Exception as e:
|
||||
@@ -343,3 +357,20 @@ def backtest_strategy(request):
|
||||
return JsonResponse({
|
||||
'error': str(e)
|
||||
}, status=500)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
def download_report(request, execution_id):
|
||||
"""백테스트 PDF 리포트 다운로드"""
|
||||
execution = get_object_or_404(StrategyExecution, id=execution_id)
|
||||
|
||||
if not execution.report_file:
|
||||
return JsonResponse({'error': 'Report not available'}, status=404)
|
||||
|
||||
file_path = os.path.join(settings.MEDIA_ROOT, execution.report_file)
|
||||
if not os.path.exists(file_path):
|
||||
return JsonResponse({'error': 'Report file not found'}, status=404)
|
||||
|
||||
response = FileResponse(open(file_path, 'rb'), content_type='application/pdf')
|
||||
response['Content-Disposition'] = f'attachment; filename="backtest_{execution_id}.pdf"'
|
||||
return response
|
||||
|
||||
Reference in New Issue
Block a user