Files
executor/CALLBACK_API_GUIDE.md

10 KiB

콜백 API 가이드

📋 개요

전략 실행 시 callback_url 파라미터를 지정하면, 전략 실행이 완료된 후 해당 URL로 결과를 POST 메서드로 자동 전송합니다.


🚀 사용 방법

1. 기본 사용 예제

curl -X POST http://localhost:8000/strategies/execute/ \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_name": "BoldAssetAllocation",
    "parameters": {
      "variant": "BAA-G4",
      "initial_capital": 100000
    },
    "callback_url": "https://your-server.com/webhook/strategy-result"
  }'

응답:

{
  "execution_id": 123,
  "status": "pending",
  "message": "Strategy execution started",
  "callback_url": "https://your-server.com/webhook/strategy-result"
}

2. 콜백 URL 없이 실행 (기존 방식)

curl -X POST http://localhost:8000/strategies/execute/ \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_name": "MovingAverageCrossover",
    "parameters": {
      "short_window": 20,
      "long_window": 50
    }
  }'

📨 콜백 페이로드

전략 실행이 완료되면 다음과 같은 JSON 데이터가 callback_url로 POST 요청됩니다.

성공 시 (status: completed)

{
  "execution_id": 123,
  "strategy": "BoldAssetAllocation",
  "version": "1.0.0",
  "status": "completed",
  "started_at": "2025-10-04T12:00:00.000Z",
  "completed_at": "2025-10-04T12:00:15.000Z",
  "execution_parameters": {
    "variant": "BAA-G4",
    "initial_capital": 100000,
    "use_real_data": false
  },
  "result": {
    "strategy": "BoldAssetAllocation",
    "variant": "BAA-G4",
    "portfolio": {
      "offensive_assets": ["VTI", "VEA"],
      "weights": {
        "VTI": 0.5,
        "VEA": 0.5
      }
    },
    "final_value": 125000,
    "return": 0.25
  }
}

실패 시 (status: failed)

{
  "execution_id": 124,
  "strategy": "BoldAssetAllocation",
  "version": "1.0.0",
  "status": "failed",
  "started_at": "2025-10-04T12:05:00.000Z",
  "completed_at": "2025-10-04T12:05:02.000Z",
  "execution_parameters": {
    "variant": "INVALID"
  },
  "error_message": "Unknown variant: INVALID. Available variants: BAA-G12, BAA-G4, ..."
}

🔍 실행 상태 확인

콜백 전송 정보를 포함한 실행 상태 조회:

curl http://localhost:8000/executions/123/

응답:

{
  "execution_id": 123,
  "strategy": "BoldAssetAllocation",
  "version": "1.0.0",
  "status": "completed",
  "started_at": "2025-10-04T12:00:00.000Z",
  "completed_at": "2025-10-04T12:00:15.000Z",
  "execution_parameters": {...},
  "result": {...},
  "callback": {
    "url": "https://your-server.com/webhook/strategy-result",
    "sent": true,
    "sent_at": "2025-10-04T12:00:15.500Z",
    "response": {
      "status_code": 200,
      "response_text": "{\"status\": \"received\"}",
      "headers": {
        "Content-Type": "application/json"
      }
    }
  }
}

🛠️ 콜백 서버 구현 예제

Python (Flask)

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhook/strategy-result', methods=['POST'])
def strategy_callback():
    data = request.json

    execution_id = data['execution_id']
    status = data['status']

    if status == 'completed':
        result = data['result']
        print(f"전략 실행 완료 (ID: {execution_id})")
        print(f"최종 수익률: {result.get('return', 0) * 100:.2f}%")

        # 결과를 데이터베이스에 저장하거나 다른 처리
        # save_to_database(data)

    elif status == 'failed':
        error_message = data['error_message']
        print(f"전략 실행 실패 (ID: {execution_id}): {error_message}")

        # 에러 알림 전송
        # send_error_notification(data)

    return jsonify({'status': 'received'}), 200

if __name__ == '__main__':
    app.run(port=8888)

Node.js (Express)

const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhook/strategy-result', (req, res) => {
    const { execution_id, status, result, error_message } = req.body;

    if (status === 'completed') {
        console.log(`전략 실행 완료 (ID: ${execution_id})`);
        console.log(`최종 수익률: ${(result.return * 100).toFixed(2)}%`);

        // 결과 처리
        // saveToDatabase(req.body);

    } else if (status === 'failed') {
        console.error(`전략 실행 실패 (ID: ${execution_id}): ${error_message}`);

        // 에러 처리
        // sendErrorNotification(req.body);
    }

    res.json({ status: 'received' });
});

app.listen(8888, () => {
    console.log('콜백 서버 시작: http://localhost:8888');
});

Django View

from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
import json

@csrf_exempt
def strategy_callback(request):
    if request.method == 'POST':
        data = json.loads(request.body)

        execution_id = data['execution_id']
        status = data['status']

        if status == 'completed':
            # 결과 처리
            result = data['result']
            print(f"전략 실행 완료: {result}")

        elif status == 'failed':
            # 에러 처리
            error = data['error_message']
            print(f"전략 실행 실패: {error}")

        return JsonResponse({'status': 'received'})

    return JsonResponse({'error': 'Method not allowed'}, status=405)

🧪 테스트 방법

1. 자동 테스트 스크립트 사용

python test_callback.py

이 스크립트는:

  • 로컬에 콜백 수신 서버를 자동으로 시작
  • 전략 실행 요청 (콜백 URL 포함)
  • 콜백 수신 및 결과 출력

2. 수동 테스트

터미널 1 - 콜백 서버:

python -m http.server 8888

터미널 2 - 전략 실행:

curl -X POST http://localhost:8000/strategies/execute/ \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_name": "MovingAverageCrossover",
    "parameters": {
      "short_window": 10,
      "long_window": 30
    },
    "callback_url": "http://localhost:8888/callback"
  }'

3. 외부 테스트 도구

webhook.site 사용:

  1. https://webhook.site 방문
  2. 생성된 고유 URL 복사
  3. 해당 URL을 callback_url로 사용
curl -X POST http://localhost:8000/strategies/execute/ \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_name": "BoldAssetAllocation",
    "parameters": {"variant": "BAA-G4"},
    "callback_url": "https://webhook.site/your-unique-id"
  }'
  1. webhook.site에서 실시간으로 수신된 데이터 확인

⚙️ 설정 및 동작

콜백 타임아웃

콜백 POST 요청은 10초 타임아웃이 설정되어 있습니다.

재시도 정책

현재 콜백은 1회만 시도합니다. 실패 시 재시도하지 않습니다.

실패 시 callback_response에 에러 정보가 저장됩니다:

{
  "callback": {
    "url": "https://unavailable.com/webhook",
    "sent": false,
    "sent_at": null,
    "response": {
      "error": "Connection refused"
    }
  }
}

보안 고려사항

  1. HTTPS 사용 권장: 프로덕션 환경에서는 HTTPS 콜백 URL 사용
  2. 서명 검증: 콜백 요청의 진위 확인을 위해 서명 메커니즘 고려
  3. IP 화이트리스트: 알려진 IP에서만 콜백 수신
  4. Rate Limiting: 과도한 요청 방지

📊 활용 사례

1. Slack 알림

import requests

@app.route('/webhook/strategy-result', methods=['POST'])
def strategy_callback():
    data = request.json

    if data['status'] == 'completed':
        result = data['result']
        message = f"✅ 전략 실행 완료\n" \
                  f"전략: {data['strategy']}\n" \
                  f"수익률: {result.get('return', 0) * 100:.2f}%"
    else:
        message = f"❌ 전략 실행 실패\n" \
                  f"오류: {data['error_message']}"

    # Slack Webhook
    requests.post(
        'https://hooks.slack.com/services/YOUR/WEBHOOK/URL',
        json={'text': message}
    )

    return jsonify({'status': 'ok'})

2. 이메일 전송

from django.core.mail import send_mail

@csrf_exempt
def strategy_callback(request):
    data = json.loads(request.body)

    if data['status'] == 'completed':
        subject = f"전략 실행 완료: {data['strategy']}"
        message = f"수익률: {data['result']['return'] * 100:.2f}%"

        send_mail(
            subject,
            message,
            'noreply@yoursite.com',
            ['admin@yoursite.com'],
        )

    return JsonResponse({'status': 'sent'})

3. 데이터베이스 저장

@csrf_exempt
def strategy_callback(request):
    data = json.loads(request.body)

    StrategyResult.objects.create(
        execution_id=data['execution_id'],
        strategy_name=data['strategy'],
        status=data['status'],
        result=data.get('result'),
        error=data.get('error_message'),
        completed_at=data.get('completed_at')
    )

    return JsonResponse({'status': 'saved'})

🐛 문제 해결

콜백이 전송되지 않음

확인사항:

  1. callback_url이 올바른 형식인지 확인
  2. 콜백 서버가 실행 중인지 확인
  3. 방화벽/보안 그룹 설정 확인
  4. 실행 상태 API에서 callback.response 확인
curl http://localhost:8000/executions/{ID}/ | python -m json.tool

타임아웃 발생

콜백 서버의 응답 시간이 10초를 초과하는 경우:

해결책:

  • 콜백 핸들러에서 빠르게 200 응답 후 백그라운드 처리
  • 타임아웃 값 조정 필요 시 views.pytimeout=10 수정

localhost 콜백이 작동하지 않음

Docker 컨테이너 내부에서 실행 중인 경우:

해결책:

  • localhost 대신 호스트 IP 사용
  • Docker: host.docker.internal 사용 (Mac/Windows)
  • ngrok 등으로 로컬 서버 외부 노출

📚 참고

  • API 전체 가이드: API_USAGE_GUIDE.md
  • BAA 전략 설명: BAA_STRATEGY_README.md
  • 배포 가이드: DEPLOYMENT_GUIDE.md

🔄 업데이트 로그

날짜 변경 내용
2025-10-04 콜백 기능 최초 구현