{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a93db194",
   "metadata": {
    "papermill": {
     "duration": 0.007252,
     "end_time": "2026-10-29T21:45:07.182017+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:07.174765+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# 매수 타점 찾기\n",
    "\n",
    "1년간 주가 데이터의 **시가·고가·저가·종가 괴리율** 평균을 계산해서 매수 타점 기준을 찾습니다.\n",
    "\n",
    "분석 지표:\n",
    "- 당일 고가 대비 종가 평균 하락율\n",
    "- 저가 vs 전일 종가 괴리율 (장중 갭다운 근사)\n",
    "- 시가 대비 저가 괴리율\n",
    "- 전일 종가 vs 당일 고가 괴리율\n",
    "- 시가 대비 고가 괴리율\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "483af113",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-29T21:45:07.193792Z",
     "iopub.status.busy": "2026-10-29T21:45:07.193505Z",
     "iopub.status.idle": "2026-10-29T21:45:07.203649Z",
     "shell.execute_reply": "2026-10-29T21:45:07.201410Z"
    },
    "papermill": {
     "duration": 0.018721,
     "end_time": "2026-10-29T21:45:07.205508+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:07.186787+00:00",
     "status": "completed"
    },
    "tags": [
     "parameters"
    ]
   },
   "outputs": [],
   "source": [
    "# ★ Parameters (papermill이 실행 시 override)\n",
    "# 여러 종목은 쉼표로 구분: \"삼성전자, 카카오, AAPL\"\n",
    "tickers_input = \"삼성전자\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bd61ac25",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-29T21:45:07.210981Z",
     "iopub.status.busy": "2026-10-29T21:45:07.210613Z",
     "iopub.status.idle": "2026-10-29T21:45:07.217357Z",
     "shell.execute_reply": "2026-10-29T21:45:07.216479Z"
    },
    "papermill": {
     "duration": 0.01077,
     "end_time": "2026-10-29T21:45:07.218730+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:07.207960+00:00",
     "status": "completed"
    },
    "tags": [
     "injected-parameters"
    ]
   },
   "outputs": [],
   "source": [
    "# Parameters\n",
    "tickers_input = \"HD\\ud604\\ub300\\uc77c\\ub809\\ud2b8\\ub9ad, \\ud6a8\\uc131\\uc911\\uacf5\\uc5c5\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c25a9342",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-29T21:45:07.226838Z",
     "iopub.status.busy": "2026-10-29T21:45:07.226595Z",
     "iopub.status.idle": "2026-10-29T21:45:09.907423Z",
     "shell.execute_reply": "2026-10-29T21:45:09.906762Z"
    },
    "papermill": {
     "duration": 2.688148,
     "end_time": "2026-10-29T21:45:09.909978+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:07.221830+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 라이브러리 + taebuji_common import\n",
    "import yfinance as yf\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import sys, os\n",
    "from pathlib import Path\n",
    "\n",
    "_TB = os.path.dirname(os.path.abspath(\"__file__\")) if \"__file__\" in dir() else \"/Users/loonshots/룬샤시_공시정리/태버지\"\n",
    "if _TB not in sys.path:\n",
    "    sys.path.insert(0, _TB)\n",
    "from taebuji_common import SessionManager, get_shared_session\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d934f507",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-29T21:45:09.916568Z",
     "iopub.status.busy": "2026-10-29T21:45:09.916379Z",
     "iopub.status.idle": "2026-10-29T21:45:25.326728Z",
     "shell.execute_reply": "2026-10-29T21:45:25.326234Z"
    },
    "papermill": {
     "duration": 15.41436,
     "end_time": "2026-10-29T21:45:25.328870+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:09.914510+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "KRX KOSPI fetch failed: Expecting value: line 1 column 1 (char 0)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "KRX KOSDAQ fetch failed: HTTPSConnectionPool(host='data.krx.co.kr', port=443): Read timed out. (read timeout=15)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using fallback hardcoded map (22 stocks)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "분석 종목: ['HD현대일렉트릭', '효성중공업']\n"
     ]
    }
   ],
   "source": [
    "# 종목명 → Yahoo 티커 변환\n",
    "def resolve_yahoo_ticker(query: str) -> str:\n",
    "    q = (query or \"\").strip()\n",
    "    if not q:\n",
    "        return \"\"\n",
    "    # 이미 Yahoo 티커 형식이면 그대로\n",
    "    if \".\" in q or (q.isascii() and (q.isupper() or q[0].isalpha())):\n",
    "        return q\n",
    "    # 6자리 숫자 → .KS (KOSPI) 기본값 (코스닥이면 사용자가 .KQ 명시 필요)\n",
    "    if q.isdigit() and len(q) == 6:\n",
    "        return q + \".KS\"\n",
    "    # 한국 종목명 → KRX에서 찾기 (Kronos stock_map 재활용)\n",
    "    try:\n",
    "        sys.path.insert(0, \"/Users/loonshots/projects/predict/OHLCV 기반\")\n",
    "        from stock_map import resolve_stock, code_to_name\n",
    "        code = resolve_stock(q)\n",
    "        if code:\n",
    "            # KRX 종목 코드가 KOSDAQ인지 확인 (간단 휴리스틱: 코스닥은 .KQ)\n",
    "            # 여기서는 .KS 기본 사용, 실패하면 .KQ 재시도\n",
    "            return code + \".KS\"\n",
    "    except Exception:\n",
    "        pass\n",
    "    # fallback: 그대로\n",
    "    return q\n",
    "\n",
    "\n",
    "tickers = [resolve_yahoo_ticker(t.strip()) for t in tickers_input.split(\",\") if t.strip()]\n",
    "print(f\"분석 종목: {tickers}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "09c9b101",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-29T21:45:25.339379Z",
     "iopub.status.busy": "2026-10-29T21:45:25.339251Z",
     "iopub.status.idle": "2026-10-29T21:45:25.346114Z",
     "shell.execute_reply": "2026-10-29T21:45:25.345547Z"
    },
    "papermill": {
     "duration": 0.012647,
     "end_time": "2026-10-29T21:45:25.346494+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:25.333847+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 매수타점 분석 함수\n",
    "def analyze_buypoint(ticker: str, period: str = \"1y\") -> dict:\n",
    "    \"\"\"ticker의 1년간 괴리율 평균을 계산.\"\"\"\n",
    "    try:\n",
    "        df = yf.download(ticker, period=period, auto_adjust=False, progress=False)\n",
    "    except Exception as e:\n",
    "        # .KS 실패 시 .KQ로 재시도 (한국 6자리 숫자만)\n",
    "        base = ticker.replace(\".KS\", \"\").replace(\".KQ\", \"\")\n",
    "        if base.isdigit() and len(base) == 6:\n",
    "            ticker = base + \".KQ\"\n",
    "            df = yf.download(ticker, period=period, auto_adjust=False, progress=False)\n",
    "        else:\n",
    "            raise\n",
    "\n",
    "    if df.empty:\n",
    "        return {\"ticker\": ticker, \"error\": \"데이터 없음\"}\n",
    "\n",
    "    # MultiIndex column 정리 (yfinance 최신 버전)\n",
    "    if isinstance(df.columns, pd.MultiIndex):\n",
    "        df.columns = df.columns.get_level_values(0)\n",
    "\n",
    "    # 1. 저가 vs 전일 종가 괴리율\n",
    "    df[\"low_vs_prev_close\"] = (df[\"Low\"] - df[\"Close\"].shift(1)) / df[\"Close\"].shift(1) * 100\n",
    "    # 2. 고가 vs 종가 하락율\n",
    "    df[\"high_to_close\"] = (df[\"Close\"] - df[\"High\"]) / df[\"High\"] * 100\n",
    "    # 3. 시가 vs 저가 괴리율\n",
    "    df[\"open_to_low\"] = (df[\"Low\"] - df[\"Open\"]) / df[\"Open\"] * 100\n",
    "    # 4. 전일 종가 vs 당일 고가 괴리율\n",
    "    df[\"prev_close_to_high\"] = (df[\"High\"] - df[\"Close\"].shift(1)) / df[\"Close\"].shift(1) * 100\n",
    "    # 5. 시가 vs 고가 괴리율\n",
    "    df[\"open_to_high\"] = (df[\"High\"] - df[\"Open\"]) / df[\"Open\"] * 100\n",
    "\n",
    "    # 종목 이름\n",
    "    try:\n",
    "        company = yf.Ticker(ticker).info.get(\"longName\") or yf.Ticker(ticker).info.get(\"shortName\") or ticker\n",
    "    except Exception:\n",
    "        company = ticker\n",
    "\n",
    "    return {\n",
    "        \"ticker\": ticker,\n",
    "        \"company\": company,\n",
    "        \"period_range\": f\"{df.index[0].date()} ~ {df.index[-1].date()}\",\n",
    "        \"samples\": len(df),\n",
    "        \"high_to_close_pct\": df[\"high_to_close\"].mean(),\n",
    "        \"low_vs_prev_close_pct\": df[\"low_vs_prev_close\"].dropna().mean(),\n",
    "        \"open_to_low_pct\": df[\"open_to_low\"].mean(),\n",
    "        \"prev_close_to_high_pct\": df[\"prev_close_to_high\"].dropna().mean(),\n",
    "        \"open_to_high_pct\": df[\"open_to_high\"].mean(),\n",
    "    }\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "90007e36",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-29T21:45:25.348701Z",
     "iopub.status.busy": "2026-10-29T21:45:25.348622Z",
     "iopub.status.idle": "2026-10-29T21:45:30.078229Z",
     "shell.execute_reply": "2026-10-29T21:45:30.077889Z"
    },
    "papermill": {
     "duration": 4.73131,
     "end_time": "2026-10-29T21:45:30.078729+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:25.347419+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "📊 분석 중: HD현대일렉트릭\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "HTTP Error 404: {\"quoteSummary\":{\"result\":null,\"error\":{\"code\":\"Not Found\",\"description\":\"Quote not found for symbol: HD현대일렉트릭\"}}}\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "$HD현대일렉트릭: No data found, symbol may be delisted\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "1 Failed download:\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "['HD현대일렉트릭']: No data found, symbol may be delisted\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  ⚠️ 데이터 없음\n",
      "\n",
      "📊 분석 중: 효성중공업\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "HTTP Error 404: {\"quoteSummary\":{\"result\":null,\"error\":{\"code\":\"Not Found\",\"description\":\"Quote not found for symbol: 효성중공업\"}}}\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "$효성중공업: No data found, symbol may be delisted\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "1 Failed download:\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "['효성중공업']: No data found, symbol may be delisted\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  ⚠️ 데이터 없음\n"
     ]
    }
   ],
   "source": [
    "# 각 종목별 분석 실행\n",
    "results = []\n",
    "for t in tickers:\n",
    "    print(f\"\\n📊 분석 중: {t}\")\n",
    "    try:\n",
    "        r = analyze_buypoint(t)\n",
    "        results.append(r)\n",
    "        if \"error\" in r:\n",
    "            print(f\"  ⚠️ {r['error']}\")\n",
    "            continue\n",
    "        print(f\"  [{r['ticker']}] ({r['company']})\")\n",
    "        print(f\"  데이터: {r['period_range']} ({r['samples']}일)\")\n",
    "        print(f\"  당일 고가 대비 종가 평균 하락율:     {r['high_to_close_pct']:.2f}%\")\n",
    "        print(f\"  당일 저가가 전일 종가 대비 괴리율:   {r['low_vs_prev_close_pct']:.2f}%\")\n",
    "        print(f\"  시가 대비 저가 평균 괴리율:          {r['open_to_low_pct']:.2f}%\")\n",
    "        print(f\"  전일 종가 대비 당일 고가 평균 괴리율: {r['prev_close_to_high_pct']:.2f}%\")\n",
    "        print(f\"  당일 시가 대비 당일 고가 평균 괴리율: {r['open_to_high_pct']:.2f}%\")\n",
    "    except Exception as e:\n",
    "        print(f\"  ❌ 실패: {type(e).__name__}: {e}\")\n",
    "        results.append({\"ticker\": t, \"error\": str(e)})\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ee6b0b97",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-29T21:45:30.081461Z",
     "iopub.status.busy": "2026-10-29T21:45:30.081384Z",
     "iopub.status.idle": "2026-10-29T21:45:30.085707Z",
     "shell.execute_reply": "2026-10-29T21:45:30.085376Z"
    },
    "papermill": {
     "duration": 0.00606,
     "end_time": "2026-10-29T21:45:30.086077+00:00",
     "exception": false,
     "start_time": "2026-10-29T21:45:30.080017+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "유효한 결과 없음\n"
     ]
    }
   ],
   "source": [
    "# 결과 표로 정리\n",
    "from IPython.display import display\n",
    "valid = [r for r in results if \"error\" not in r]\n",
    "if valid:\n",
    "    df_result = pd.DataFrame([\n",
    "        {\n",
    "            \"티커\": r[\"ticker\"],\n",
    "            \"종목명\": r[\"company\"],\n",
    "            \"고가→종가 하락율\": f\"{r['high_to_close_pct']:.2f}%\",\n",
    "            \"저가 vs 전일종가\": f\"{r['low_vs_prev_close_pct']:.2f}%\",\n",
    "            \"시가 vs 저가\": f\"{r['open_to_low_pct']:.2f}%\",\n",
    "            \"전일종가 vs 고가\": f\"{r['prev_close_to_high_pct']:.2f}%\",\n",
    "            \"시가 vs 고가\": f\"{r['open_to_high_pct']:.2f}%\",\n",
    "        }\n",
    "        for r in valid\n",
    "    ])\n",
    "    print(\"\\n📋 종합 결과:\")\n",
    "    display(df_result)\n",
    "else:\n",
    "    print(\"유효한 결과 없음\")\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.13"
  },
  "papermill": {
   "default_parameters": {},
   "duration": 24.432366,
   "end_time": "2026-10-29T21:45:30.403224+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/Users/seog-yejun/룬샤시_공시정리/태버지/5. 매수타점 찾기.ipynb",
   "output_path": "/Users/seog-yejun/룬샤시_공시정리/태버지/5. 매수타점 찾기.ipynb",
   "parameters": {
    "tickers_input": "HD현대일렉트릭, 효성중공업"
   },
   "start_time": "2026-10-29T21:45:05.970858+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}