{
  "ticker": "278470.KS",
  "ticker_name": "에이피알",
  "status": "success",
  "trade_date": "2026-04-14",
  "analysis_date": "2026-04-14",
  "decision": "{\n  \"rating\": \"NO_TRADE\",\n  \"portfolio_stance\": \"BULLISH\",\n  \"entry_action\": \"WAIT\",\n  \"setup_quality\": \"DEVELOPING\",\n  \"confidence\": 0.72,\n  \"time_horizon\": \"medium\",\n  \"entry_logic\": \"278470.KS에 대한 방향성 판단은 긍정적이다. 공격적 분석가와 중립 분석가가 지적했듯이 주가는 10일 지수이동평균, 50일 단순이동평균, 200일 단순이동평균 위에 있고, MACD가 7,766.53에서 17,098.65로 재가속했으며 히스토그램도 4,836.91로 양전했다. 펀더멘털도 매출과 영업이익 급증, 약 23.8% 영업이익률, 약 19.0% 순이익률, 75% 이상 ROE, Q4 약 KRW 150.8 billion 자유현금흐름, 미국 성장과 유럽 확장 기대가 뒷받침한다. 다만 즉시 매수는 보류한다. 2026-04-13 종가 KRW 399,500은 KRW 408,500 저항에 근접했고, 10일 지수이동평균 대비 약 11.9%, 50일 단순이동평균 대비 약 28.7%, 200일 단순이동평균 대비 약 66% 위에 있어 진입 안전마진이 낮다. RSI는 약 68로 과열권에 가깝고, ATR은 약 KRW 24,942로 가격의 약 6.24%이며, 거래량은 2026-04-09의 868,166주 급증 이후 2026-04-13의 286,905주로 식었다. 따라서 신규 자금은 KRW 356,000-365,000 구간으로 질서 있는 조정이 나오고 종가 기준 지지가 확인되거나, KRW 408,500을 강한 거래량과 후속 흐름으로 돌파할 때까지 기다린다. 조건이 충족되면 소규모 시작 포지션은 정당화될 수 있지만, 오늘의 진입 조건은 아직 완성되지 않았다.\",\n  \"exit_logic\": \"기존 보유자는 중기 추세와 펀더멘털이 유지되는 동안 보유 가능하되, 위험은 줄여서 관리한다. KRW 393,000-408,500 부근에서 RSI가 70을 넘고 거래량이 약해지는 실패가 반복되면 단순한 저항 소화인지 분배인지 점검한다. KRW 356,000 종가 이탈은 단기 모멘텀 훼손으로 보고 전술적 비중을 줄인다. KRW 330,000-345,000 하향 이탈은 수급 악화 신호로 더 큰 감축이 필요하다. KRW 310,000 부근을 결정적으로 종가 이탈하면 50일선 방어 실패와 중기 추세 훼손으로 판단해 투자 논리를 무효화한다. 또한 Q1 실적이나 가이던스가 높아진 기대를 넘지 못하거나, 판매마케팅비가 매출보다 빠르게 증가해 마진을 압박하거나, 재고가 KRW 165.5 billion 수준에서 다시 확대되거나, 미국 및 유럽 성장이 실제 소비 수요가 아닌 채널 재고 축적에 그친다는 증거가 나오면 축소 또는 청산한다.\",\n  \"position_sizing\": \"오늘 신규 풀사이즈 포지션은 열지 않는다. 기존 보유자는 고변동 성장주 기준으로도 정상 비중 이하를 유지한다. 진입 조건이 확인될 경우 첫 매수는 정상 비중의 약 1/3로 제한하고, Q1에서 매출 성장, 영업이익률 방어, 마케팅 효율, 재고 통제, 미국 및 유럽 실판매가 확인될 때만 최대 1/2 정상 비중까지 허용한다. 추가 매수는 KRW 408,500 돌파 후 지지 전환이 확인되거나, 10일 지수이동평균 부근 위에서 더 높은 저점을 만든 뒤에만 검토한다. ATR이 하루 약 6.24%인 만큼 레버리지는 사용하지 않는다.\",\n  \"risk_limits\": \"거래 위험은 평소보다 낮게 배정한다. KRW 408,500 위로 갭 상승하더라도 거래량과 후속 종가 확인 없이 추격하지 않는다. 2026-04-13 거래량 286,905주를 소폭 넘는 수준만으로는 충분하지 않으며, 2026-04-09의 868,166주 급증을 고려해 뚜렷한 참여 확대 또는 돌파 후 재시험 성공을 요구한다. 손절과 감축 판단은 장중 흔들림보다 일봉 종가와 거래량 성격을 우선한다. KRW 356,000 이탈 시 전술 리스크를 줄이고, KRW 330,000-345,000 이탈 시 비중을 크게 낮추며, KRW 310,000 이탈 시 중기 투자 논리를 폐기한다.\",\n  \"catalysts\": [\n    \"278470.KS Q1 실적이 높아진 시장 기대를 명확히 상회\",\n    \"미국 오프라인 및 온라인 채널에서 반복 수요 기반 매출 성장 지속\",\n    \"유럽 확장이 측정 가능한 매출 기여로 전환\",\n    \"2026-03-31 기업가치 제고 공시의 실행 세부 내용 구체화\",\n    \"실적 추정치 또는 목표주가 추가 상향이 실제 수치 개선으로 뒷받침\",\n    \"KRW 408,500 상향 돌파가 강한 거래량과 후속 종가로 확인\"\n  ],\n  \"invalidators\": [\n    \"SK Securities 목표가 KRW 510,000 상향 이후 Q1 실적 또는 가이던스가 단순 부합에 그침\",\n    \"판매마케팅비가 KRW 166.5 billion에서 KRW 255.5 billion으로 증가한 뒤 매출보다 빠르게 늘어 영업이익률을 압박\",\n    \"재고가 KRW 165.5 billion 수준에서 다시 확대되어 할인 또는 채널 재고 위험을 키움\",\n    \"미국 성장이 반복 소비 수요가 아니라 채널 채우기였다는 증거\",\n    \"유럽 확장에 예상보다 큰 판촉비, 물류비, 유통 지원 비용이 필요\",\n    \"KRW 310,000 결정적 종가 이탈\"\n  ],\n  \"watchlist_triggers\": [\n    \"KRW 356,000-365,000 조정 구간에서 종가 기준 지지와 안정된 거래량 확인 시 시작 포지션 검토\",\n    \"KRW 408,500 위 종가 돌파와 286,905주를 뚜렷하게 넘는 거래량 확대, 가능하면 다음 거래일 후속 강세 또는 재시험 성공 확인\",\n    \"KRW 393,000-408,500 부근에서 RSI 70 이상, 거래량 약화, 다음 종가 약세가 동시에 나타나면 경계 강화\",\n    \"KRW 356,000 종가 이탈 시 단기 모멘텀 경고\",\n    \"KRW 330,000-345,000 종가 이탈 시 수급 악화로 비중 축소\",\n    \"Q1 공시에서 매출 성장률, 영업이익률, 마케팅 효율, 재고, 미국 실판매, 유럽 매출 기여 확인\"\n  ],\n  \"data_coverage\": {\n    \"company_news_count\": 3,\n    \"disclosures_count\": 3,\n    \"social_source\": \"news_derived\",\n    \"macro_items_count\": 0\n  }\n}",
  "started_at": "2026-04-14T12:34:10.598027+09:00",
  "finished_at": "2026-04-14T12:48:43.110784+09:00",
  "duration_seconds": 872.51,
  "metrics": {
    "llm_calls": 66,
    "tool_calls": 22,
    "tokens_in": 0,
    "tokens_out": 0,
    "tokens_available": false,
    "calls_by_model": {
      "gpt-5.4": 66
    }
  },
  "tool_telemetry": {
    "total_tool_calls": 22,
    "vendor_calls": {
      "yfinance": 15,
      "naver": 3,
      "ecos": 1,
      "opendart": 1,
      "alpha_vantage": 2
    },
    "fallback_count": 4,
    "events": [
      {
        "method": "get_stock_data",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_indicators",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_social_sentiment",
        "vendor": "naver",
        "status": "fallback",
        "fallback": true,
        "note": "naver: empty or unusable result"
      },
      {
        "method": "get_company_news",
        "vendor": "naver",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_social_sentiment",
        "vendor": "yfinance",
        "status": "fallback",
        "fallback": true,
        "note": "yfinance: empty or unusable result"
      },
      {
        "method": "get_macro_news",
        "vendor": "ecos",
        "status": "fallback",
        "fallback": true,
        "note": "ecos: ECOS API key is not configured."
      },
      {
        "method": "get_disclosures",
        "vendor": "opendart",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_macro_news",
        "vendor": "alpha_vantage",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_company_news",
        "vendor": "naver",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_income_statement",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_cashflow",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_balance_sheet",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_insider_transactions",
        "vendor": "yfinance",
        "status": "fallback",
        "fallback": true,
        "note": "yfinance: empty or unusable result"
      },
      {
        "method": "get_fundamentals",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_insider_transactions",
        "vendor": "alpha_vantage",
        "status": "success",
        "fallback": false,
        "note": null
      }
    ]
  },
  "quality_flags": [
    "token_usage_unavailable"
  ],
  "report_writer": {
    "status": "fallback",
    "scope": "ticker",
    "provider": "codex",
    "model": "gpt-5.4",
    "reason": "writer_failed",
    "error": "1 validation error for CodexChatModel\ncodex_workspace_dir\n  Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]\n    For further information visit https://errors.pydantic.dev/2.12/v/string_type"
  },
  "provider": "codex",
  "models": {
    "quick_model": "gpt-5.4",
    "deep_model": "gpt-5.4",
    "output_model": "gpt-5.4"
  }
}