{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e9c64b69",
   "metadata": {},
   "source": [
    "# 量化交易工作坊 · 任务四：海龟交易策略（Turtle Trading）\n",
    "\n",
    "**标的：芯动联科（688582.SH）**\n",
    "\n",
    "本 Notebook 完成以下工作：\n",
    "1. 阐述海龟策略的**核心思想**与**关键优势**；\n",
    "2. 解释海龟策略三大核心构件：**高低点通道（Donchian Channel）**、**平均真实波幅（ATR）**、**止损条件**；\n",
    "3. Python 实现：加载股价数据 → 计算 20 日高低点通道 → 计算 ATR → 生成买卖信号 → 可视化（股价/通道/信号/止损）→ 模拟交易与回测 → 计算 MDD / 夏普 / 累计回报；\n",
    "4. 调节股票与通道周期，观察收益变化并总结海龟法则的适应场景与心得。\n",
    "\n",
    "> 说明：本 Notebook 复用 `app/turtle_lib.py` 中的策略引擎，仅需 `pandas / numpy / matplotlib`。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae2b0e5b",
   "metadata": {},
   "source": [
    "## 一、海龟策略核心思想与关键优势\n",
    "\n",
    "### 1. 起源与核心思想\n",
    "海龟策略源于 1983 年华尔街传奇交易员 Richard Dennis 与 William Eckhardt 的著名实验：Dennis 认为**优秀的交易员可以被\"训练\"出来**，于是从千名报名者中选拔了 13 人（\"海龟\"），用两周时间传授一套完整的、机械化的趋势跟踪交易系统，并给他们实盘资金。结果海龟们在接下来四年里创造了年均 80% 以上的收益，证明了**一套纪律严明的系统化方法，可以战胜天赋**。\n",
    "\n",
    "海龟策略的核心思想可以概括为三点：\n",
    "\n",
    "- **趋势跟踪（Trend Following）**：价格会沿某一方向持续运行（动量效应），通过\"突破\"捕捉趋势的起点；\n",
    "- **分散化与组合**：同时在多个市场、多个时间周期上交易，让少数大赢家覆盖多数小亏损；\n",
    "- **严格的风险管理**：用**波动率（ATR）**统一度量风险，并以\"**固定比例账户风险**\"确定仓位，任何单笔交易亏损都被严格限制。\n",
    "\n",
    "### 2. 关键优势\n",
    "1. **风险可控**：仓位由 ATR 决定，波动大的标的自动少买、波动小的多买，使每笔交易承受相近的风险；\n",
    "2. **止损纪律**：2N 硬止损 + ½N 跟踪止损，让利润奔跑、亏损截断，避免情绪化扛单；\n",
    "3. **完全机械化**：买卖信号由规则明确给出，消除了主观判断与\"该不该卖\"的人性纠结；\n",
    "4. **捕捉大趋势**：突破入场天然站在趋势一边，一旦趋势展开，回报丰厚且回撤有限；\n",
    "5. **普适性强**：同一套逻辑可套用到股票、商品、外汇等任何有趋势的市场。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a54ad5d3",
   "metadata": {},
   "source": [
    "## 二、海龟策略三大核心构件\n",
    "\n",
    "### 1. 高低点通道（Donchian Channel，唐奇安通道）\n",
    "取过去 $N$ 日（如 20 日）的**最高价**作为通道上轨、**最低价**作为通道下轨：\n",
    "\n",
    "$$\\text{Upper}_t = \\max(High_{t-N+1}, \\dots, High_{t-1}), \\quad \\text{Lower}_t = \\min(Low_{t-N+1}, \\dots, Low_{t-1})$$\n",
    "\n",
    "- 当收盘价**向上突破上轨** → 入场做多信号（趋势启动）；\n",
    "- 当收盘价**向下跌破下轨** → 离场信号（趋势终结）。\n",
    "\n",
    "为避免\"未来函数\"，计算通道时排除当日，用截至昨日的历史极值判断今日是否突破。\n",
    "\n",
    "### 2. 平均真实波幅（ATR，Average True Range）\n",
    "真实波幅 TR 度量单日价格的\"真实摆动幅度\"，考虑了跳空：\n",
    "\n",
    "$$TR_t = \\max(High_t-Low_t,\\ |High_t-Close_{t-1}|,\\ |Low_t-Close_{t-1}|)$$\n",
    "\n",
    "$$ATR_t = \\text{mean}(TR_{t-N+1}, \\dots, TR_t)$$\n",
    "\n",
    "ATR 是海龟体系的\"风险度量尺\"：它不直接预测方向，而是告诉你\"这只股票最近每天平均波动多大\"，从而统一为所有标的标定仓位与止损幅度。\n",
    "\n",
    "### 3. 止损条件\n",
    "海龟用两类止损保护本金：\n",
    "\n",
    "- **初始止损（2N 止损）**：入场后，在 `入场价 − 2×ATR` 处挂止损。价格触及即离场，单笔最大亏损约等于 2% 账户（因为仓位按 1% 风险 ÷ ATR 设置）；\n",
    "- **跟踪止损（½N 台阶）**：只要持仓盈利，止损价就按每 `½×ATR` 的台阶向上移动，把浮盈逐步\"锁\"住，既给趋势回调留出空间，又能在反转时保住大部分利润。\n",
    "\n",
    "两者结合，实现了\"小亏大赚\"的风险收益结构。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "21b4d2e0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 环境准备：引入策略引擎与中文字体\n",
    "import os, sys\n",
    "sys.path.insert(0, os.path.abspath(\"../app\"))   # turtle_lib.py 位于 app/ 目录\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "from turtle_lib import (load_data, donchian_channel, compute_atr,\n",
    "                        turtle_backtest, make_turtle_figure,\n",
    "                        make_atr_figure, make_equity_figure)\n",
    "\n",
    "DATA = os.path.join(os.path.abspath(\"..\"), \"data\")\n",
    "print(\"数据目录:\", DATA)\n",
    "print(\"可用文件:\", [f for f in os.listdir(DATA) if f.endswith(\".csv\") and not f.startswith(\"_\")])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "981a6796",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1) 加载已存储的股价数据\n",
    "df = load_data(os.path.join(DATA, \"688582.SH.csv\"))\n",
    "print(\"芯动联科 行数:\", len(df), \"  区间:\", df['trade_date'].iloc[0], \"->\", df['trade_date'].iloc[-1])\n",
    "df[[\"trade_date\", \"open\", \"high\", \"low\", \"close\", \"vol\"]].head()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8ae14e9",
   "metadata": {},
   "source": [
    "## 三、Python 实现：海龟策略全流程\n",
    "\n",
    "下面按任务要求逐步完成：设定通道周期 → 计算高低点通道 → 计算 ATR → 计算买卖信号 → 绘图 → 回测指标。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c9cf5bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 2) 设定高低点通道周期（如 20），计算高低点通道\n",
    "CHANNEL = 20\n",
    "df = donchian_channel(df, CHANNEL)\n",
    "print(\"上轨(前20日最高价)与下轨(前20日最低价)已计算，示例：\")\n",
    "df[[\"trade_date\", \"high\", \"low\", \"close\", f\"upper_{CHANNEL}\", f\"lower_{CHANNEL}\"]].iloc[18:24]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "161b6d9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 3) 计算 ATR 数值（取 20 日）\n",
    "ATR_P = 20\n",
    "df = compute_atr(df, ATR_P)\n",
    "print(\"ATR 前若干值（前 20 日为 NaN，因为需要足够样本）：\")\n",
    "df[[\"trade_date\", \"high\", \"low\", \"close\", \"tr\", \"atr\"]].iloc[18:26].round(3)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5087446a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4) 计算买入 / 卖出交易信号（含模拟交易回测）\n",
    "# turtle_backtest 内部：突破上轨做多(仓位=1%风险/ATR)、2N止损+½N跟踪止损、跌破下轨离场\n",
    "res = turtle_backtest(df, channel_period=CHANNEL, atr_period=ATR_P, initial=1_000_000)\n",
    "df = res[\"df\"]\n",
    "m = res[\"metrics\"]\n",
    "print(f\"买入信号次数: {int(df['buy'].sum())}   卖出信号次数: {int(df['sell'].sum())}\")\n",
    "print(f\"持仓天数:     {int((df['position']>0).sum())} / {len(df)}\")\n",
    "df[[\"trade_date\",\"close\",f\"upper_{CHANNEL}\",f\"lower_{CHANNEL}\",\"atr\",\"position\",\"buy\",\"sell\",\"stop\"]].iloc[19:40]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76f1d941",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 5) 绘制可视化图形：股价 + 高低点通道 + 买卖信号 + 止损线（图1）\n",
    "fig = make_turtle_figure(df, CHANNEL,\n",
    "    title=f\"图1  芯动联科(688582.SH) 海龟策略信号图（通道={CHANNEL}）\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc5e4663",
   "metadata": {},
   "source": [
    "**图1 解读**：上图展示芯动联科（688582.SH）的收盘价（深蓝）、20 日高低点通道（橙/绿虚线）、买入信号▲（突破上轨）与卖出信号▼（跌破下轨或触及止损），以及红色 ½N 跟踪止损线（起点为入场价 −2N 止损）。可见海龟策略在价格向上突破通道时果断入场，并随盈利把跟踪止损线（红）按 ½N 台阶逐步上移；当价格回落跌破通道或触碰跟踪止损即离场。图中出场点明显早于一轮完整上涨的顶端，体现\"截断亏损、让利润奔跑\"但也会\"卖早\"的权衡。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "da7ccd9f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 图2：ATR 走势（市场波动水平）\n",
    "fig = make_atr_figure(df, ATR_P,\n",
    "    title=f\"图2  芯动联科(688582.SH) ATR({ATR_P}) 平均真实波幅\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dca53380",
   "metadata": {},
   "source": [
    "**图2 解读**：ATR 反映标的每日的平均波动幅度。芯动联科作为高弹性半导体股，ATR 长期处于较高水平且随行情放大（如 2024—2025 的主升段），这意味着同样 1% 的账户风险对应的股数更少、止损空间更宽。海龟用 ATR 把\"波动\"量化，使得在不同波动环境、不同标的之间，单笔风险保持恒定——这是其风控的核心。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "31438850",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 图3：策略净值 vs 买入持有基准\n",
    "fig = make_equity_figure(df, CHANNEL,\n",
    "    title=f\"图3  芯动联科(688582.SH) 海龟策略净值 vs 买入持有\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9abe08a7",
   "metadata": {},
   "source": [
    "**图3 解读**：红线为海龟策略净值，蓝虚线为买入持有（基准）净值。在 2023-06-30 至 2026-07-10 区间，海龟策略（通道=20）累计回报约 +2.90%，最大回撤仅约 −9.3%，明显小于买入持有的 −22.5% 回撤；但同期收益也低于买入持有（因频繁在强趋势中离场）。这说明海龟是\"以收益换稳健\"的风险管理型策略——在下行或震荡市中优势显著，在单边暴涨市中易\"卖飞\"。从交易质量看，本组参数下海龟胜率约 59%、盈亏比约 0.72：胜率虽高于双均线，但因单笔 2N 止损触发的亏损相对平均盈利更大，盈亏比小于 1，收益主要来自少数大趋势行情的\"截断亏损、让利润奔跑\"。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf24cfd9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 6) 模拟交易与回测，计算量化指标\n",
    "print(\"========== 海龟策略回测指标（芯动联科，通道=20）==========\")\n",
    "print(f\"累计回报   : {m['cumulative_return']*100:7.2f}%\")\n",
    "print(f\"基准(买入持有): {m['benchmark_return']*100:7.2f}%\")\n",
    "print(f\"超额收益   : {m['excess_return']*100:7.2f}%\")\n",
    "print(f\"最大回撤MDD : {m['mdd']*100:7.2f}%\")\n",
    "print(f\"夏普比率   : {m['sharpe']:7.2f}\")\n",
    "print(f\"年化收益   : {m['annualized_return']*100:7.2f}%\")\n",
    "print(f\"胜率       : {m['win_rate']*100:7.2f}%\")\n",
    "print(f\"盈亏比     : {m['pl_ratio']:7.2f}\")\n",
    "print(f\"交易次数   : {m['n_trades']}\")\n",
    "print(f\"期末净值   : {m['final_equity']:,.0f} 元\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92067bb9",
   "metadata": {},
   "source": [
    "上述指标均基于**按信号逐日模拟交易**得到（次日按前一日持仓调仓、触及止损/通道即离场，避免未来函数）。累计回报衡量总收益，最大回撤衡量最坏情景下的浮亏深度，夏普比率衡量\"每单位风险的超额收益\"——三者共同刻画策略的盈利性与稳健性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4a1f1ce6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 四、调节参数：不同股票 × 不同通道周期，观察收益变化\n",
    "import os as _os\n",
    "stocks = [(\"688582.SH\",\"芯动联科\"), (\"600519.SH\",\"贵州茅台\"),\n",
    "          (\"300750.SZ\",\"宁德时代\"), (\"000001.SZ\",\"平安银行\")]\n",
    "periods = [20, 55]\n",
    "rows = []\n",
    "for code, name in stocks:\n",
    "    p = _os.path.join(DATA, f\"{code}.csv\")\n",
    "    if not _os.path.exists(p):\n",
    "        continue\n",
    "    d0 = load_data(p)\n",
    "    for cp in periods:\n",
    "        r = turtle_backtest(d0, channel_period=cp, atr_period=cp, initial=1_000_000)\n",
    "        mm = r[\"metrics\"]\n",
    "        rows.append({\n",
    "            \"股票\": name, \"代码\": code, \"通道\": cp,\n",
    "            \"累计回报\": f\"{mm['cumulative_return']*100:.2f}%\",\n",
    "            \"基准\": f\"{mm['benchmark_return']*100:.2f}%\",\n",
    "            \"超额\": f\"{mm['excess_return']*100:.2f}%\",\n",
    "            \"MDD\": f\"{mm['mdd']*100:.2f}%\",\n",
    "            \"Sharpe\": f\"{mm['sharpe']:.2f}\",\n",
    "            \"交易\": mm[\"n_trades\"],\n",
    "        })\n",
    "cmp = pd.DataFrame(rows)\n",
    "cmp\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "06d99731",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 保存对比结果供报告使用\n",
    "cmp.to_csv(_os.path.join(DATA, \"_turtle_comparison.csv\"), index=False)\n",
    "to_num = lambda s: pd.to_numeric(s.astype(str).str.replace('%','',regex=False), errors='coerce')\n",
    "for col in [\"累计回报\",\"基准\",\"超额\",\"MDD\",\"Sharpe\"]:\n",
    "    cmp[col] = to_num(cmp[col])\n",
    "print(\"各标的在不同通道下的平均表现：\")\n",
    "cmp.groupby(\"股票\")[[\"累计回报\",\"Sharpe\",\"MDD\"]].mean().round(2)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc2841c3",
   "metadata": {},
   "source": [
    "## 五、海龟法则的适应场景与使用心得\n",
    "\n",
    "### 1. 适应场景\n",
    "- **趋势明确的市场**：海龟是趋势跟踪策略，在存在中期以上趋势（如 2024—2025 的半导体上行）时能充分获益；\n",
    "- **高波动、高流动性标的**：ATR 风控需要足够的波动来产生信号、也需要流动性来成交，因此适合成交活跃的股票/商品/外汇；\n",
    "- **下行或震荡市场中的\"防守优势\"**：如图表所示，在贵州茅台（区间 −30%）、平安银行（区间 −24%）这类下跌标的上，海龟凭借 2N 止损把回撤压到 −5%~−16%，并显著跑赢买入持有——这是其最耀眼的场景。\n",
    "\n",
    "### 2. 不适应的场景\n",
    "- **单边暴涨市**：强趋势中 2N 止损会过早离场（芯动联科海龟 +2.9% vs 买入持有 +22.5%），\"卖飞\"明显；\n",
    "- **纯震荡（无趋势）市**：价格反复穿越通道，产生连续假突破，频繁小额止损（洗损）。\n",
    "\n",
    "### 3. 通道周期的选择\n",
    "对比 20 日与 55 日通道可见：**周期越长，信号越少、越平滑、夏普通常更高、回撤更可控**（如芯动联科 55 日 MDD −6.75% < 20 日 −9.32%）；周期越短，反应灵敏但噪音多、交易频繁。实战中常**双周期并行**（原版 S1=20/S2=55 组合）以兼顾灵敏度与稳健性。\n",
    "\n",
    "### 4. 总体心得\n",
    "海龟策略的真正价值不在\"某次赚多少\"，而在**用一套可复制的纪律把交易中的人性弱点（贪婪、恐惧、犹豫）剔除**。它用 ATR 统一风险刻度、用 2N 止损守住本金、用突破捕捉趋势——这套\"风险优先、趋势其次\"的框架，是后续构建任何量化策略都应继承的底层思维。\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
