{
  "ticker": "010950.KS",
  "ticker_name": "S-Oil",
  "status": "success",
  "trade_date": "2026-04-15",
  "analysis_date": "2026-04-16",
  "decision": "{\n  \"rating\": \"HOLD\",\n  \"portfolio_stance\": \"BULLISH\",\n  \"entry_action\": \"WAIT\",\n  \"setup_quality\": \"DEVELOPING\",\n  \"confidence\": 0.61,\n  \"time_horizon\": \"medium\",\n  \"entry_logic\": \"010950.KS는 중기 방향성은 건설적이지만 오늘 즉시 신규 진입할 위치는 아니다. 공격적 분석가가 지적한 대로 4월 14일 종가 119100은 10일 EMA 116585, 50일 SMA 111859, 200일 SMA 81354, VWMA 약 114045 위에 있고, MACD 2252.66이 신호선 1236.39 위에 있으며 RSI 55.28도 과열이 아니다. 또한 4Q25 영업이익 3719억 KRW, 순이익 2251억 KRW, 영업현금흐름 1.86조 KRW, 자유현금흐름 6134억 KRW, 순부채 6.38조 KRW에서 5.70조 KRW로 개선된 점은 보유 근거다. 다만 보수적·중립 분석가가 강조한 120700-124500 저항, 3월 4일 대량거래와 176551 고점이 만든 매물 부담, 4월 15일 유가 급락에 따른 재고손실·정제마진 불확실성, 기관 순매도, 약 7455 KRW의 높은 ATR 때문에 신규 자금은 확인 전까지 대기한다. 진입은 124500 상향 돌파와 거래량 확장 후 지지 확인, 또는 116500-114000 구간 조정에서 VWMA와 단기 지지가 유지되고 마진 뉴스가 악화되지 않을 때만 정당화된다.\",\n  \"exit_logic\": \"기존 010950.KS 보유분은 114000이 유지되고 50일 SMA 부근 111800이 훼손되지 않는 한 핵심 또는 벤치마크 수준으로 유지한다. 114000을 거래량 동반 이탈하거나 111800 부근이 실패하면 post-event 회복 구조가 깨진 것으로 보고 축소 또는 청산한다. 유가 변동이 재고손실과 제품마진 악화로 이어지거나, 기관 매도가 다음 흐름 업데이트 이후에도 지속되거나, 대규모 capex와 부채 부담이 최근 순부채 개선을 상쇄하는 경우도 청산 사유다.\",\n  \"position_sizing\": \"신규 매수는 지금 실행하지 않는다. 기존 보유는 핵심 또는 벤치마크 비중으로 제한하고 저항대 아래에서 추격 매수하지 않는다. 124500 돌파와 거래량 확인 또는 116500-114000 지지 확인이 나오면 ATR 약 7455 KRW와 약 6% 변동성을 반영해 정상 비중의 절반 이하 starter만 허용한다. 124500 위에서 지지 재확인과 기관 수급 개선이 동반될 때만 추가한다.\",\n  \"risk_limits\": \"초기 위험 예산은 정상보다 낮게 둔다. 전술 위험선은 114000, 중기 논리 훼손선은 111800으로 설정한다. 높은 ATR 때문에 촘촘한 장중 손절은 피하되, 50일 SMA 아래에서는 새로운 실적·정제마진 촉매 없이 물타기하지 않는다. 유가, 정제마진, FX, capex, 유동성 압박을 핵심 위험 변수로 관리한다.\",\n  \"catalysts\": [\n    \"010950.KS가 120700을 종가 기준 회복하고 124500 위로 거래량 확장과 함께 안착한다.\",\n    \"124500 돌파 후 되돌림에서 해당 구간을 지지로 확인해 3월 4일 매물 부담을 흡수한다.\",\n    \"정제마진이 안정 또는 개선되고 4월 15일 유가 충격이 재고손실로 확대되지 않는다.\",\n    \"010950.KS 기관 순매도가 둔화되거나 순매수로 전환된다.\",\n    \"2026 실적 업데이트가 4Q25 영업이익 회복과 자유현금흐름 개선이 반복 가능하다는 점을 확인한다.\",\n    \"국민연금 공시 세부 내용이 지분 축소가 아니라 안정적 또는 증가한 보유를 시사한다.\"\n  ],\n  \"invalidators\": [\n    \"010950.KS가 120700-124500 저항에서 반복적으로 실패하고 거래량이 약해진다.\",\n    \"114000을 지속적으로 이탈한 뒤 50일 SMA 부근 111800도 훼손한다.\",\n    \"유가 변동성이 재고손실과 제품마진 악화로 연결된다.\",\n    \"capex 초과 또는 부채 부담 증가가 순부채 개선을 상쇄한다.\",\n    \"영업현금흐름 개선이 운전자본 효과에 그쳤다는 증거가 강화된다.\",\n    \"기관 매도와 정제마진 불확실성 중심의 뉴스 흐름이 실적 상향 없이 계속된다.\"\n  ],\n  \"watchlist_triggers\": [\n    \"010950.KS 일봉 종가가 120700 위로 올라서고 거래량이 최근 평균보다 증가한다.\",\n    \"124500 위 돌파와 유지로 post-event 공급 흡수를 확인한다.\",\n    \"116500-114000 조정 구간에서 VWMA와 단기 추세가 지지되고 부정적 마진 뉴스가 추가되지 않는다.\",\n    \"010950.KS 기관 수급이 순매수 또는 매도 둔화로 전환된다.\",\n    \"다음 실적 또는 가이던스가 영업이익, 자유현금흐름, capex 관리 가능성을 확인한다.\",\n    \"ATR이 추가로 안정되면서 114000-111800 위험 구간을 침범하지 않는다.\"\n  ],\n  \"data_coverage\": {\n    \"company_news_count\": 4,\n    \"disclosures_count\": 1,\n    \"social_source\": \"news_derived\",\n    \"macro_items_count\": 1\n  }\n}",
  "started_at": "2026-04-16T02:03:57.613527+09:00",
  "finished_at": "2026-04-16T02:20:34.602034+09:00",
  "duration_seconds": 996.99,
  "metrics": {
    "llm_calls": 58,
    "tool_calls": 22,
    "tokens_in": 0,
    "tokens_out": 0,
    "tokens_available": false,
    "calls_by_model": {
      "gpt-5.4": 58
    }
  },
  "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_balance_sheet",
        "vendor": "yfinance",
        "status": "success",
        "fallback": false,
        "note": null
      },
      {
        "method": "get_cashflow",
        "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
      }
    ],
    "called_tools": [],
    "intraday_snapshot_used": false
  },
  "quality_flags": [
    "token_usage_unavailable"
  ],
  "report_writer": {
    "status": "success",
    "scope": "ticker",
    "provider": "codex",
    "model": "gpt-5.4"
  },
  "provider": "codex",
  "models": {
    "quick_model": "gpt-5.4",
    "deep_model": "gpt-5.4",
    "output_model": "gpt-5.4"
  }
}