Add dc_only parameter to all strategy endpoints. When true, filters results to include only tickers present in the ETF table, supporting DC pension investment constraints where only ETFs are allowed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
138 lines
3.8 KiB
Python
138 lines
3.8 KiB
Python
"""
|
|
E2E tests for quant strategy flow.
|
|
"""
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
def test_multi_factor_strategy(client: TestClient, auth_headers):
|
|
"""Test multi-factor strategy endpoint."""
|
|
response = client.post(
|
|
"/api/strategy/multi-factor",
|
|
json={
|
|
"universe": {
|
|
"markets": ["KOSPI"],
|
|
"min_market_cap": 10000, # 1조원 (억원 단위)
|
|
},
|
|
"top_n": 20,
|
|
"weights": {
|
|
"value": 0.3,
|
|
"quality": 0.3,
|
|
"momentum": 0.2,
|
|
"low_vol": 0.2,
|
|
},
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
# May fail if no stock data, just check it returns a proper response
|
|
assert response.status_code in [200, 400, 500]
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
assert "stocks" in data
|
|
assert "strategy_name" in data
|
|
assert data["strategy_name"] == "multi_factor"
|
|
|
|
|
|
def test_quality_strategy(client: TestClient, auth_headers):
|
|
"""Test quality strategy endpoint."""
|
|
response = client.post(
|
|
"/api/strategy/quality",
|
|
json={
|
|
"universe": {
|
|
"markets": ["KOSPI"],
|
|
"min_market_cap": 10000,
|
|
},
|
|
"top_n": 20,
|
|
"min_fscore": 6,
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert response.status_code in [200, 400, 500]
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
assert "stocks" in data
|
|
assert data["strategy_name"] == "quality"
|
|
|
|
|
|
def test_value_momentum_strategy(client: TestClient, auth_headers):
|
|
"""Test value-momentum strategy endpoint."""
|
|
response = client.post(
|
|
"/api/strategy/value-momentum",
|
|
json={
|
|
"universe": {
|
|
"markets": ["KOSPI"],
|
|
"min_market_cap": 10000,
|
|
},
|
|
"top_n": 20,
|
|
"value_weight": 0.5,
|
|
"momentum_weight": 0.5,
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert response.status_code in [200, 400, 500]
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
assert "stocks" in data
|
|
assert data["strategy_name"] == "value_momentum"
|
|
|
|
|
|
def test_dc_only_filter(client: TestClient, auth_headers):
|
|
"""Test dc_only parameter filters to ETFs only."""
|
|
response = client.post(
|
|
"/api/strategy/multi-factor",
|
|
json={
|
|
"universe": {
|
|
"markets": ["KOSPI"],
|
|
},
|
|
"top_n": 20,
|
|
"dc_only": True,
|
|
"weights": {
|
|
"value": 0.3,
|
|
"quality": 0.3,
|
|
"momentum": 0.2,
|
|
"low_vol": 0.2,
|
|
},
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
# May fail if no data, just check it accepts the parameter
|
|
assert response.status_code in [200, 400, 500]
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
assert "stocks" in data
|
|
# All returned stocks should be ETFs (or empty if no ETFs in universe)
|
|
|
|
|
|
def test_dc_only_false_returns_all(client: TestClient, auth_headers):
|
|
"""Test dc_only=false returns all stocks (default behavior)."""
|
|
response = client.post(
|
|
"/api/strategy/multi-factor",
|
|
json={
|
|
"universe": {
|
|
"markets": ["KOSPI"],
|
|
},
|
|
"top_n": 20,
|
|
"dc_only": False,
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert response.status_code in [200, 400, 500]
|
|
|
|
|
|
def test_strategy_requires_auth(client: TestClient):
|
|
"""Test that strategy endpoints require authentication."""
|
|
response = client.post(
|
|
"/api/strategy/multi-factor",
|
|
json={
|
|
"universe": {
|
|
"markets": ["KOSPI"],
|
|
},
|
|
"top_n": 20,
|
|
},
|
|
)
|
|
assert response.status_code == 401
|