<essential principles <principle name="cot as flow proxy" COT 週資料作為資金流代理 CFTC Commitments of Traders 報告是追蹤對沖基金農產品部位的核心資料: - 截止日 :每週二收盤 - 發布日 :每週五下午 3:30 ET - 交易者分類 :非商業(投機/基金)、商業(避險)、非報告 資金流 = 本週淨部位 - 上週淨部位(以合約口數計) </principle <principle name="group aggregation" 分組彙總邏輯 使用 CFTC 原生分組(commodity subgroup name): | 群組 | CFTC 分組名稱 | 包含商品 | |----------|-------------------------|-----------------------------------| | Grains | GRAINS | Corn, Wheat (SRW/HRW/HRS), Oats | | Oilseeds | OILSEED and PRODUCTS | Soybeans, Soybean Oil/Meal, Canola| | Meats | LIVESTOCK/MEAT PRODUCTS | Live Cattle, Lean Hogs, Fee…

\u003c>=\")\n url = f\"{CFTC_API_URL}?{encoded_params}\"\n\n print(f\"Fetching COT data from CFTC API...\")\n print(f\" Date range: {start_date} to {end_date}\")\n\n response = requests.get(url, timeout=120)\n response.raise_for_status()\n\n data = response.json()\n print(f\" Records fetched: {len(data)}\")\n\n if not data:\n print(\" Warning: No data returned from API\")\n return pd.DataFrame()\n\n df = pd.DataFrame(data)\n return df\n\n\ndef parse_cot_data(df: pd.DataFrame) -> pd.DataFrame:\n \"\"\"\n 解析 COT 資料,提取需要的欄位並計算淨部位\n\n Args:\n df: Raw DataFrame from API\n\n Returns:\n Parsed DataFrame with standardized columns\n \"\"\"\n if df.empty:\n return pd.DataFrame()\n\n # 提取並重命名欄位\n result = pd.DataFrame({\n \"date\": pd.to_datetime(df[\"report_date_as_yyyy_mm_dd\"]).dt.date,\n \"contract\": df[\"contract_market_name\"],\n \"cftc_code\": df[\"cftc_contract_market_code\"],\n \"subgroup_name\": df[\"commodity_subgroup_name\"],\n \"open_interest\": pd.to_numeric(df[\"open_interest_all\"], errors=\"coerce\"),\n \"long\": pd.to_numeric(df[\"noncomm_positions_long_all\"], errors=\"coerce\"),\n \"short\": pd.to_numeric(df[\"noncomm_positions_short_all\"], errors=\"coerce\"),\n \"spreading\": pd.to_numeric(df.get(\"noncomm_postions_spread_all\", 0), errors=\"coerce\"),\n })\n\n # 映射到標準群組\n result[\"group\"] = result[\"subgroup_name\"].map(CFTC_GROUP_MAP)\n\n # 過濾掉未知群組\n unknown = result[result[\"group\"].isna()]\n if len(unknown) > 0:\n print(f\" Warning: {len(unknown)} records with unknown subgroup:\")\n for sg in unknown[\"subgroup_name\"].unique():\n print(f\" - {sg}\")\n result = result[result[\"group\"].notna()].copy()\n\n # 計算淨部位\n result[\"net_pos\"] = result[\"long\"] - result[\"short\"]\n\n return result\n\n\ndef calculate_flows(df: pd.DataFrame) -> pd.DataFrame:\n \"\"\"\n 計算資金流(週變化)\n\n Args:\n df: Parsed COT DataFrame\n\n Returns:\n DataFrame with flow column added\n \"\"\"\n if df.empty:\n return df\n\n df = df.sort_values([\"contract\", \"date\"]).copy()\n\n # 計算每個合約的週變化\n df[\"flow\"] = df.groupby(\"contract\")[\"net_pos\"].diff()\n\n return df\n\n\ndef aggregate_by_group(df: pd.DataFrame) -> tuple[pd.DataFrame, pd.DataFrame]:\n \"\"\"\n 按群組彙總流量與淨部位\n\n Args:\n df: COT DataFrame with flows\n\n Returns:\n Tuple of (flows_df, positions_df) pivoted by group\n \"\"\"\n if df.empty:\n return pd.DataFrame(), pd.DataFrame()\n\n # 流量彙總\n flows = df.groupby([\"date\", \"group\"])[\"flow\"].sum().unstack(fill_value=0)\n for g in ALL_GROUPS:\n if g not in flows.columns:\n flows[g] = 0\n flows[\"total\"] = flows[ALL_GROUPS].sum(axis=1)\n\n # 淨部位彙總\n positions = df.groupby([\"date\", \"group\"])[\"net_pos\"].sum().unstack(fill_value=0)\n for g in ALL_GROUPS:\n if g not in positions.columns:\n positions[g] = 0\n positions[\"total\"] = positions[ALL_GROUPS].sum(axis=1)\n\n return flows.sort_index(), positions.sort_index()\n\n\ndef get_latest_week_summary(df: pd.DataFrame) -> Dict:\n \"\"\"\n 取得最新一週的摘要\n\n Args:\n df: COT DataFrame with flows\n\n Returns:\n Dictionary with latest week metrics\n \"\"\"\n if df.empty:\n return {}\n\n latest_date = df[\"date\"].max()\n latest = df[df[\"date\"] == latest_date]\n\n # 按群組彙總\n group_summary = latest.groupby(\"group\").agg({\n \"net_pos\": \"sum\",\n \"flow\": \"sum\",\n \"long\": \"sum\",\n \"short\": \"sum\",\n \"open_interest\": \"sum\",\n }).to_dict(\"index\")\n\n # 計算總計\n total_net = latest[\"net_pos\"].sum()\n total_flow = latest[\"flow\"].sum()\n\n return {\n \"date\": str(latest_date),\n \"total_net_pos\": int(total_net),\n \"total_flow\": int(total_flow) if pd.notna(total_flow) else None,\n \"by_group\": {\n g: {\n \"net_pos\": int(v[\"net_pos\"]),\n \"flow\": int(v[\"flow\"]) if pd.notna(v[\"flow\"]) else None,\n \"long\": int(v[\"long\"]),\n \"short\": int(v[\"short\"]),\n \"open_interest\": int(v[\"open_interest\"]),\n }\n for g, v in group_summary.items()\n },\n }\n\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Fetch CFTC COT data via Socrata API\")\n parser.add_argument(\n \"--start\",\n type=str,\n default=(datetime.now() - timedelta(days=365 * 3)).strftime(\"%Y-%m-%d\"),\n help=\"Start date (YYYY-MM-DD), default: 3 years ago\",\n )\n parser.add_argument(\n \"--end\",\n type=str,\n default=datetime.now().strftime(\"%Y-%m-%d\"),\n help=\"End date (YYYY-MM-DD), default: today\",\n )\n parser.add_argument(\n \"--output\",\n type=str,\n default=\"cache/cot_data.parquet\",\n help=\"Output file path\",\n )\n parser.add_argument(\n \"--summary\",\n action=\"store_true\",\n help=\"Print latest week summary\",\n )\n\n args = parser.parse_args()\n\n # 抓取資料\n raw_df = fetch_cot_from_api(args.start, args.end)\n\n if raw_df.empty:\n print(\"Error: No data fetched\")\n return 1\n\n # 解析資料\n df = parse_cot_data(raw_df)\n\n # 計算流量\n df = calculate_flows(df)\n\n # 確保輸出目錄存在\n output_path = Path(args.output)\n output_path.parent.mkdir(parents=True, exist_ok=True)\n\n # 儲存\n df.to_parquet(output_path, index=False)\n print(f\"\\nCOT data saved to {output_path}\")\n print(f\" Date range: {df['date'].min()} to {df['date'].max()}\")\n print(f\" Unique contracts: {df['contract'].nunique()}\")\n print(f\" Total records: {len(df)}\")\n\n # 顯示最新週摘要\n if args.summary:\n summary = get_latest_week_summary(df)\n print(f\"\\n{'='*50}\")\n print(f\"Latest Week Summary ({summary['date']})\")\n print(f\"{'='*50}\")\n print(f\"Total Net Position: {summary['total_net_pos']:,}\")\n print(f\"Total Weekly Flow: {summary['total_flow']:,}\" if summary['total_flow'] else \"Total Weekly Flow: N/A (first week)\")\n print(f\"\\nBy Group:\")\n for g, v in summary.get(\"by_group\", {}).items():\n flow_str = f\"{v['flow']:+,}\" if v['flow'] is not None else \"N/A\"\n print(f\" {g:12} | Net: {v['net_pos']:>10,} | Flow: {flow_str:>10} | OI: {v['open_interest']:>12,}\")\n\n return 0\n\n\nif __name__ == \"__main__\":\n exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":8138,"content_sha256":"7afdbe1fb0a8f5dc122a4d260ca4ddb0d31e8b087ae6cebcabea50c89ce036a1"},{"filename":"scripts/fetch_macro_data.py","content":"#!/usr/bin/env python3\n\"\"\"\n宏觀指標抓取腳本\n\n從 Yahoo Finance 和 FRED 抓取宏觀指標資料。\n\"\"\"\n\nimport argparse\nfrom datetime import datetime, timedelta\nfrom io import StringIO\nfrom pathlib import Path\nfrom typing import Dict\n\nimport pandas as pd\nimport requests\n\n# 嘗試導入 yfinance\ntry:\n import yfinance as yf\n HAS_YFINANCE = True\nexcept ImportError:\n HAS_YFINANCE = False\n print(\"Warning: yfinance not installed, using FRED fallback\")\n\n\n# 預設指標設定\nDEFAULT_INDICATORS = {\n \"usd\": {\n \"yahoo\": \"UUP\",\n \"fred\": \"DTWEXBGS\",\n \"description\": \"美元指數代理 (Invesco DB US Dollar Index)\",\n },\n \"crude\": {\n \"yahoo\": \"CL=F\",\n \"fred\": \"DCOILWTICO\",\n \"description\": \"WTI 原油期貨\",\n },\n \"metals\": {\n \"yahoo\": \"XME\",\n \"fred\": None,\n \"description\": \"SPDR S&P Metals & Mining ETF\",\n },\n \"agri\": {\n \"yahoo\": \"DBA\",\n \"fred\": None,\n \"description\": \"Invesco DB Agriculture Fund\",\n },\n \"gold\": {\n \"yahoo\": \"GC=F\",\n \"fred\": None,\n \"description\": \"黃金期貨\",\n },\n}\n\nFRED_CSV_URL = \"https://fred.stlouisfed.org/graph/fredgraph.csv\"\n\n\ndef fetch_yahoo_series(symbol: str, start_date: str, end_date: str) -> pd.Series:\n \"\"\"從 Yahoo Finance 抓取序列\"\"\"\n if not HAS_YFINANCE:\n raise ImportError(\"yfinance not installed\")\n\n print(f\" Downloading {symbol} from Yahoo Finance...\")\n df = yf.download(symbol, start=start_date, end=end_date, progress=False)\n\n if df.empty:\n print(f\" Warning: No data returned for {symbol}\")\n return pd.Series(dtype=float, name=symbol)\n\n # 處理 MultiIndex columns(yfinance 新版本格式)\n if isinstance(df.columns, pd.MultiIndex):\n # 取 Close 價格\n if \"Close\" in df.columns.get_level_values(0):\n series = df[\"Close\"].iloc[:, 0]\n else:\n # 取第一個價格列\n series = df.iloc[:, 0]\n else:\n # 舊版格式\n if \"Adj Close\" in df.columns:\n series = df[\"Adj Close\"]\n elif \"Close\" in df.columns:\n series = df[\"Close\"]\n else:\n series = df.iloc[:, 0]\n\n series.name = symbol\n return series\n\n\ndef fetch_fred_series(series_id: str, start_date: str, end_date: str) -> pd.Series:\n \"\"\"從 FRED 抓取序列(無需 API key)\"\"\"\n params = {\n \"id\": series_id,\n \"cosd\": start_date,\n \"coed\": end_date,\n }\n\n print(f\" Downloading {series_id} from FRED...\")\n\n try:\n response = requests.get(FRED_CSV_URL, params=params, timeout=30)\n response.raise_for_status()\n\n df = pd.read_csv(StringIO(response.text))\n df.columns = [\"DATE\", series_id]\n df[\"DATE\"] = pd.to_datetime(df[\"DATE\"])\n df[series_id] = df[series_id].replace(\".\", pd.NA)\n df[series_id] = pd.to_numeric(df[series_id], errors=\"coerce\")\n df = df.dropna().set_index(\"DATE\")\n\n return df[series_id]\n\n except Exception as e:\n print(f\" Error fetching {series_id} from FRED: {e}\")\n return pd.Series(dtype=float, name=series_id)\n\n\ndef fetch_indicator(\n indicator_name: str,\n start_date: str,\n end_date: str,\n source: str = \"yahoo\",\n) -> pd.Series:\n \"\"\"抓取單一指標\"\"\"\n config = DEFAULT_INDICATORS.get(indicator_name)\n if config is None:\n raise ValueError(f\"Unknown indicator: {indicator_name}\")\n\n # 優先使用 Yahoo Finance\n if source == \"yahoo\" and HAS_YFINANCE:\n symbol = config.get(\"yahoo\")\n if symbol:\n try:\n series = fetch_yahoo_series(symbol, start_date, end_date)\n if len(series) > 0:\n series.name = indicator_name\n return series\n except Exception as e:\n print(f\" Yahoo fetch failed: {e}\")\n\n # Fallback to FRED\n fred_id = config.get(\"fred\")\n if fred_id:\n series = fetch_fred_series(fred_id, start_date, end_date)\n series.name = indicator_name\n return series\n\n print(f\" Warning: No data source available for {indicator_name}\")\n return pd.Series(dtype=float, name=indicator_name)\n\n\ndef fetch_all_indicators(\n start_date: str,\n end_date: str,\n indicators: list = None,\n) -> pd.DataFrame:\n \"\"\"抓取所有指標\"\"\"\n if indicators is None:\n indicators = [\"usd\", \"crude\", \"metals\"]\n\n print(f\"Fetching macro indicators...\")\n print(f\" Date range: {start_date} to {end_date}\")\n\n data = {}\n for ind in indicators:\n print(f\"Fetching {ind}...\")\n try:\n series = fetch_indicator(ind, start_date, end_date)\n if len(series) > 0:\n data[ind] = series\n print(f\" Got {len(series)} records\")\n else:\n print(f\" Warning: No data for {ind}\")\n except Exception as e:\n print(f\" Failed: {e}\")\n\n if not data:\n print(\"Error: No indicator data fetched\")\n return pd.DataFrame()\n\n df = pd.DataFrame(data)\n df.index.name = \"date\"\n\n # 前向填充缺失值(週末/假日)\n df = df.ffill()\n\n return df\n\n\ndef calculate_returns(df: pd.DataFrame, periods: int = 5) -> pd.DataFrame:\n \"\"\"計算報酬率\"\"\"\n if df.empty:\n return pd.DataFrame()\n\n returns = df.pct_change(periods)\n returns.columns = [f\"{col}_ret\" for col in returns.columns]\n return returns\n\n\ndef calculate_tailwind_score(df: pd.DataFrame, returns_df: pd.DataFrame) -> pd.Series:\n \"\"\"計算宏觀順風評分\"\"\"\n if returns_df.empty:\n return pd.Series(dtype=float, name=\"macro_tailwind\")\n\n scores = []\n\n for date in returns_df.index:\n row = returns_df.loc[date]\n flags = []\n\n # USD 走弱 = 利於商品\n if \"usd_ret\" in row and pd.notna(row[\"usd_ret\"]):\n flags.append(row[\"usd_ret\"] \u003c 0)\n\n # 原油走強 = 風險偏好上升\n if \"crude_ret\" in row and pd.notna(row[\"crude_ret\"]):\n flags.append(row[\"crude_ret\"] > 0)\n\n # 金屬走強 = 循環需求樂觀\n if \"metals_ret\" in row and pd.notna(row[\"metals_ret\"]):\n flags.append(row[\"metals_ret\"] > 0)\n\n score = sum(flags) / len(flags) if flags else None\n scores.append(score)\n\n return pd.Series(scores, index=returns_df.index, name=\"macro_tailwind\")\n\n\ndef get_latest_tailwind_summary(df: pd.DataFrame) -> Dict:\n \"\"\"取得最新宏觀順風摘要\"\"\"\n if df.empty or \"macro_tailwind\" not in df.columns:\n return {\"score\": None, \"components\": {}}\n\n # 取最新一行有效資料\n latest = df.dropna(subset=[\"macro_tailwind\"]).iloc[-1] if len(df.dropna(subset=[\"macro_tailwind\"])) > 0 else None\n\n if latest is None:\n return {\"score\": None, \"components\": {}}\n\n score = latest[\"macro_tailwind\"]\n components = {}\n\n if \"usd_ret\" in latest and pd.notna(latest[\"usd_ret\"]):\n components[\"usd_down\"] = latest[\"usd_ret\"] \u003c 0\n components[\"usd_ret\"] = round(latest[\"usd_ret\"] * 100, 2)\n\n if \"crude_ret\" in latest and pd.notna(latest[\"crude_ret\"]):\n components[\"crude_up\"] = latest[\"crude_ret\"] > 0\n components[\"crude_ret\"] = round(latest[\"crude_ret\"] * 100, 2)\n\n if \"metals_ret\" in latest and pd.notna(latest[\"metals_ret\"]):\n components[\"metals_up\"] = latest[\"metals_ret\"] > 0\n components[\"metals_ret\"] = round(latest[\"metals_ret\"] * 100, 2)\n\n return {\n \"score\": round(score, 2) if pd.notna(score) else None,\n \"components\": components,\n \"date\": str(latest.name.date()) if hasattr(latest.name, \"date\") else str(latest.name),\n }\n\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Fetch macro indicators\")\n parser.add_argument(\n \"--indicators\",\n type=str,\n default=\"usd,crude,metals\",\n help=\"Comma-separated list of indicators\",\n )\n parser.add_argument(\n \"--start\",\n type=str,\n default=(datetime.now() - timedelta(days=30)).strftime(\"%Y-%m-%d\"),\n help=\"Start date (YYYY-MM-DD), default: 30 days ago\",\n )\n parser.add_argument(\n \"--end\",\n type=str,\n default=datetime.now().strftime(\"%Y-%m-%d\"),\n help=\"End date (YYYY-MM-DD), default: today\",\n )\n parser.add_argument(\n \"--output\",\n type=str,\n default=\"cache/macro_data.parquet\",\n help=\"Output file path\",\n )\n parser.add_argument(\n \"--summary\",\n action=\"store_true\",\n help=\"Print latest tailwind summary\",\n )\n\n args = parser.parse_args()\n\n indicators = [i.strip() for i in args.indicators.split(\",\")]\n\n # 抓取資料\n df = fetch_all_indicators(args.start, args.end, indicators)\n\n if df.empty:\n print(\"Error: No data fetched\")\n return 1\n\n # 計算報酬\n returns = calculate_returns(df, periods=5) # 5 日報酬\n\n # 計算順風評分\n tailwind = calculate_tailwind_score(df, returns)\n\n # 合併\n result = pd.concat([df, returns, tailwind], axis=1)\n\n # 確保輸出目錄存在\n output_path = Path(args.output)\n output_path.parent.mkdir(parents=True, exist_ok=True)\n\n # 儲存\n result.to_parquet(output_path)\n print(f\"\\nMacro data saved to {output_path}\")\n print(f\" Date range: {result.index.min()} to {result.index.max()}\")\n print(f\" Indicators: {list(df.columns)}\")\n print(f\" Records: {len(result)}\")\n\n # 顯示最新摘要\n if args.summary:\n summary = get_latest_tailwind_summary(result)\n print(f\"\\n{'='*50}\")\n print(f\"Latest Macro Tailwind Summary\")\n print(f\"{'='*50}\")\n if summary[\"score\"] is not None:\n print(f\"Date: {summary.get('date', 'N/A')}\")\n print(f\"Score: {summary['score']:.0%}\")\n print(\"Components:\")\n for k, v in summary[\"components\"].items():\n if \"_ret\" in k:\n print(f\" {k}: {v:+.2f}%\")\n else:\n print(f\" {k}: {'✓' if v else '✗'}\")\n else:\n print(\"No tailwind data available\")\n\n return 0\n\n\nif __name__ == \"__main__\":\n exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":10161,"content_sha256":"a756cd5df1ab6068ed8ba06185546129709234c0476c8069d646b175e6fa6781"},{"filename":"scripts/visualize_flows.py","content":"#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n農產品對沖基金部位視覺化\n\n生成 Bloomberg 風格的 COT 資金流分析圖表。\n\nUsage:\n python visualize_flows.py\n python visualize_flows.py --output path/to/output.png\n python visualize_flows.py --weeks 52\n\"\"\"\n\nimport argparse\nfrom datetime import datetime\nfrom pathlib import Path\nfrom typing import Dict, Any, Optional\n\nimport matplotlib\nmatplotlib.use('Agg') # 非交互式後端,必須在 import pyplot 前設定\n\nimport matplotlib.pyplot as plt\nimport matplotlib.dates as mdates\nfrom matplotlib.ticker import FuncFormatter\nfrom matplotlib.patches import Patch\nfrom matplotlib.colors import LinearSegmentedColormap\nimport numpy as np\nimport pandas as pd\n\nfrom fetch_cot_data import (\n ALL_GROUPS,\n aggregate_by_group,\n calculate_flows,\n fetch_cot_from_api,\n parse_cot_data,\n)\n\n\n# ========== Bloomberg 風格配色(依據 bloomberg-style-chart-guide.md)==========\nCOLORS = {\n # 背景與網格\n \"background\": \"#1a1a2e\",\n \"grid\": \"#2d2d44\",\n\n # 文字\n \"text\": \"#ffffff\",\n \"text_dim\": \"#888888\",\n\n # 群組配色(6 個群組)\n \"grains\": \"#ff6b35\", # 橙紅(穀物 - 主要)\n \"oilseeds\": \"#ffaa00\", # 橙黃(油籽)\n \"meats\": \"#00ff88\", # 綠色(肉類)\n \"softs\": \"#00bfff\", # 藍色(軟性商品)\n \"fiber\": \"#cc66ff\", # 紫色(纖維)\n \"dairy\": \"#ff66b2\", # 粉紅(乳製品)\n\n # 淨部位線\n \"net_pos_line\": \"#ffffff\", # 白色\n\n # 火力配色(熱圖)\n \"firepower_high\": \"#00ff88\", # 高火力(綠 = 買進空間大)\n \"firepower_mid\": \"#ffaa00\", # 中火力(橙)\n \"firepower_low\": \"#ff4444\", # 低火力(紅 = 擁擠)\n\n # 訊號配色\n \"bullish\": \"#00ff88\",\n \"bearish\": \"#ff4444\",\n \"neutral\": \"#888888\",\n\n # 輔助\n \"zero_line\": \"#666666\",\n}\n\n# 群組顯示名稱(純中文)\nGROUP_LABELS = {\n \"grains\": \"穀物\",\n \"oilseeds\": \"油籽\",\n \"meats\": \"肉類\",\n \"softs\": \"軟商品\",\n \"fiber\": \"纖維\",\n \"dairy\": \"乳製品\",\n}\n\n# 火力圖排序(由上到下):肉類 > 油籽 > 乳製品 > 穀物 > 纖維 > 軟商品\nFIREPOWER_ORDER = [\"meats\", \"oilseeds\", \"dairy\", \"grains\", \"fiber\", \"softs\"]\n\n# 中文字體設定\nplt.rcParams['font.sans-serif'] = [\n 'Microsoft JhengHei', # Windows 正黑體\n 'SimHei', # Windows 黑體\n 'Microsoft YaHei', # Windows 微軟雅黑\n 'PingFang TC', # macOS 蘋方\n 'Noto Sans CJK TC', # Linux/通用\n 'DejaVu Sans' # 備用\n]\nplt.rcParams['axes.unicode_minus'] = False\n\n\n# ========== USDA 關鍵事件標註(用於 Total 部位轉折解讀)==========\nUSDA_EVENT_ANNOTATIONS = [\n # A) 年初核心供需錨\n {\"date\": \"2025-01-10\", \"label\": \"年初供需錨\",\n \"desc\": \"WASDE+庫存+冬麥\\n全年定調起點\", \"category\": \"wasde\"},\n # B) 月度 WASDE 節點\n {\"date\": \"2025-02-11\", \"label\": \"2月WASDE\",\n \"desc\": \"修正南美/出口\\n穀物油籽情緒\", \"category\": \"wasde\"},\n {\"date\": \"2025-03-11\", \"label\": \"3月WASDE\",\n \"desc\": \"春季前校準\\n全球出口節奏\", \"category\": \"wasde\"},\n {\"date\": \"2025-04-10\", \"label\": \"4月WASDE\",\n \"desc\": \"新作年度鋪陳\\n25/26預期啟動\", \"category\": \"wasde\"},\n # C) 春季大轉折:種植意向\n {\"date\": \"2025-03-31\", \"label\": \"種植意向\",\n \"desc\": \"玉米/黃豆面積\\n供給預期重錨\", \"category\": \"planting\"},\n # D) 夏季再定錨:實際播種面積\n {\"date\": \"2025-06-30\", \"label\": \"實際面積\",\n \"desc\": \"意向→落地\\n穀物供給硬定錨\", \"category\": \"planting\"},\n # E) 收成期供給衝擊 + 資料中斷\n {\"date\": \"2025-09-12\", \"label\": \"供給巨大化\",\n \"desc\": \"玉米創紀錄預估\\n庫存大增→偏空\", \"category\": \"wasde\"},\n {\"date\": \"2025-09-30\", \"label\": \"季度庫存\",\n \"desc\": \"收成前後更新\\n穀物部位再調整\", \"category\": \"stocks\"},\n {\"date\": \"2025-10-09\", \"label\": \"資料黑箱\",\n \"desc\": \"政府停擺\\nCOT/出口數據中斷\", \"category\": \"shutdown\"},\n # F) 報告回補/延後釋出\n {\"date\": \"2025-11-14\", \"label\": \"報告回補\",\n \"desc\": \"黑箱後WASDE\\n估計分歧創高\", \"category\": \"wasde\"},\n # G) 年末供需更新 + 年度總結\n {\"date\": \"2025-12-09\", \"label\": \"年末WASDE\",\n \"desc\": \"年末供需更新\\n資金調倉節點\", \"category\": \"wasde\"},\n {\"date\": \"2026-01-12\", \"label\": \"年度總結\",\n \"desc\": \"2025產量定案\\n年初再定錨依據\", \"category\": \"summary\"},\n]\n\n# 事件類別顏色\nEVENT_CATEGORY_COLORS = {\n \"wasde\": \"#ffaa00\", # 橙黃:月度供需報告\n \"planting\": \"#00ff88\", # 綠色:種植相關\n \"stocks\": \"#00bfff\", # 藍色:庫存報告\n \"shutdown\": \"#ff4444\", # 紅色:異常事件\n \"summary\": \"#cc66ff\", # 紫色:年度總結\n}\n\n\ndef add_usda_event_annotations(ax, dates, y_bottom, y_top):\n \"\"\"\n 在圖表上添加 USDA 關鍵事件標註(簡短中文摘要)\n\n Parameters\n ----------\n ax : matplotlib.axes.Axes\n 主圖表軸\n dates : pd.DatetimeIndex\n 圖表的日期索引\n y_bottom : float\n Y 軸最小值\n y_top : float\n Y 軸最大值\n \"\"\"\n from datetime import datetime as dt, date\n\n # 將日期轉為 date 對象以便比較(統一類型)\n def to_date(d):\n if hasattr(d, 'date'):\n return d.date()\n elif hasattr(d, 'to_pydatetime'):\n return d.to_pydatetime().date()\n elif isinstance(d, date):\n return d\n return d\n\n date_list = [to_date(d) for d in dates]\n date_min = min(date_list)\n date_max = max(date_list)\n\n # 過濾出在圖表範圍內的事件\n events_in_range = []\n for event in USDA_EVENT_ANNOTATIONS:\n event_date = dt.strptime(event[\"date\"], \"%Y-%m-%d\").date()\n if date_min \u003c= event_date \u003c= date_max:\n events_in_range.append((event_date, event))\n\n if not events_in_range:\n return\n\n # 找出每個事件對應的 x 位置(最接近的週)\n for event_date, event in events_in_range:\n # 找最接近的索引\n min_diff = float('inf')\n closest_idx = 0\n for i, d in enumerate(date_list):\n diff = abs((d - event_date).days) if hasattr(d - event_date, 'days') else float('inf')\n if diff \u003c min_diff:\n min_diff = diff\n closest_idx = i\n\n # 只有在合理範圍內(±7天)才標註\n if min_diff > 7:\n continue\n\n x_pos = closest_idx\n color = EVENT_CATEGORY_COLORS.get(event[\"category\"], \"#888888\")\n\n # 繪製垂直虛線(淡化,不要太搶眼)\n ax.axvline(x=x_pos, color=color, linestyle=':', linewidth=0.8, alpha=0.4, zorder=1)\n\n # 組合標籤文字:主標籤 + 描述(換行)\n label_text = event[\"label\"]\n if \"desc\" in event and event[\"desc\"]:\n # 橫向顯示時用 | 分隔更緊湊\n desc_short = event[\"desc\"].replace(\"\\n\", \" | \")\n label_text = f\"{event['label']}\\n{desc_short}\"\n\n # 在底部區域使用多層高度避免重疊\n # 根據索引分配不同層級(0.02, 0.12, 0.22, 0.32)\n idx = events_in_range.index((event_date, event))\n layer = idx % 4 # 4 層循環\n height_offset = 0.02 + layer * 0.10\n label_y = y_bottom + (y_top - y_bottom) * height_offset\n\n # 橫向標籤(字體小,淡色背景增加可讀性)\n ax.text(x_pos, label_y, label_text,\n rotation=0, fontsize=5, color=color, alpha=0.9,\n ha='center', va='bottom', zorder=4, linespacing=0.85,\n bbox=dict(boxstyle='round,pad=0.2', facecolor=COLORS['background'],\n edgecolor=color, alpha=0.75, linewidth=0.3))\n\n\ndef setup_bloomberg_style():\n \"\"\"設定 Bloomberg 風格\"\"\"\n plt.style.use('dark_background')\n plt.rcParams.update({\n 'figure.facecolor': COLORS['background'],\n 'axes.facecolor': COLORS['background'],\n 'axes.edgecolor': COLORS['grid'],\n 'axes.labelcolor': COLORS['text'],\n 'axes.grid': True,\n 'grid.color': COLORS['grid'],\n 'grid.alpha': 0.3,\n 'grid.linestyle': '-',\n 'grid.linewidth': 0.5,\n 'text.color': COLORS['text'],\n 'xtick.color': COLORS['text_dim'],\n 'ytick.color': COLORS['text_dim'],\n 'legend.facecolor': COLORS['background'],\n 'legend.edgecolor': COLORS['grid'],\n 'legend.labelcolor': COLORS['text'],\n 'font.size': 10,\n })\n\n\ndef format_contracts(x, pos):\n \"\"\"合約數格式化(K 表示千)\"\"\"\n if abs(x) >= 1000:\n return f'{x/1000:.0f}K'\n return f'{x:.0f}'\n\n\ndef calculate_firepower_series(positions_df: pd.DataFrame, lookback_weeks: int = 156) -> pd.DataFrame:\n \"\"\"\n 計算各群組的火力時序\n\n Parameters\n ----------\n positions_df : pd.DataFrame\n 淨部位時序(columns = groups)\n lookback_weeks : int\n 回溯週數\n\n Returns\n -------\n pd.DataFrame\n 火力時序(columns = groups)\n \"\"\"\n firepower_df = pd.DataFrame(index=positions_df.index)\n\n for col in positions_df.columns:\n fp_series = []\n for i in range(len(positions_df)):\n if i \u003c 10:\n fp_series.append(np.nan)\n continue\n\n start_idx = max(0, i - lookback_weeks)\n hist = positions_df[col].iloc[start_idx:i+1]\n current = positions_df[col].iloc[i]\n\n # percentile rank\n p = (hist \u003c= current).mean()\n fp = 1 - p\n fp_series.append(fp)\n\n firepower_df[col] = fp_series\n\n return firepower_df\n\n\ndef create_positioning_chart(\n flows_df: pd.DataFrame,\n positions_df: pd.DataFrame,\n firepower_df: pd.DataFrame,\n latest_summary: Dict[str, Any],\n output_path: Optional[str] = None,\n title: str = \"農產品對沖基金部位分析\",\n weeks_to_show: int = 52,\n) -> None:\n \"\"\"\n 創建農產品對沖基金部位分析圖表(Bloomberg 風格)\n \"\"\"\n setup_bloomberg_style()\n\n # 取最近 N 週\n flows_df = flows_df.iloc[-weeks_to_show:].copy()\n positions_df = positions_df.iloc[-weeks_to_show:].copy()\n firepower_df = firepower_df.iloc[-weeks_to_show:].copy()\n\n # 建立圖表:2 行,左側大圖 + 右側資訊面板\n fig = plt.figure(figsize=(16, 10))\n fig.set_facecolor(COLORS['background'])\n\n # GridSpec: 2 行 x 4 列,左 3 列給圖表,右 1 列給資訊\n gs = fig.add_gridspec(2, 4, height_ratios=[1.5, 1], width_ratios=[1, 1, 1, 0.8],\n hspace=0.3, wspace=0.3)\n\n # ========== 圖 1: 週流量堆疊柱狀圖 + 總淨部位折線 ==========\n ax1 = fig.add_subplot(gs[0, :3])\n ax1.set_facecolor(COLORS['background'])\n\n # 準備堆疊柱狀圖數據\n dates = flows_df.index\n x = np.arange(len(dates))\n width = 0.8\n\n # 分離正負流量\n positive_flows = flows_df[ALL_GROUPS].clip(lower=0)\n negative_flows = flows_df[ALL_GROUPS].clip(upper=0)\n\n # 繪製正向堆疊\n bottom_pos = np.zeros(len(dates))\n for group in ALL_GROUPS:\n ax1.bar(x, positive_flows[group], width, bottom=bottom_pos,\n color=COLORS[group], label=GROUP_LABELS[group], alpha=0.85)\n bottom_pos += positive_flows[group].values\n\n # 繪製負向堆疊\n bottom_neg = np.zeros(len(dates))\n for group in ALL_GROUPS:\n ax1.bar(x, negative_flows[group], width, bottom=bottom_neg,\n color=COLORS[group], alpha=0.85)\n bottom_neg += negative_flows[group].values\n\n # 零線\n ax1.axhline(y=0, color=COLORS['zero_line'], linewidth=1, zorder=3)\n\n # 右軸:總淨部位折線\n ax1_twin = ax1.twinx()\n ax1_twin.plot(x, positions_df['total'] / 1000, color=COLORS['net_pos_line'],\n linewidth=2.5, label='總淨部位(右軸)', zorder=5)\n ax1_twin.set_ylabel('總淨部位(千合約)', color=COLORS['text'], fontsize=10)\n ax1_twin.tick_params(axis='y', labelcolor=COLORS['text'])\n\n # 標註最新淨部位\n latest_pos = positions_df['total'].iloc[-1]\n ax1_twin.annotate(f'{latest_pos/1000:+,.0f}K',\n xy=(x[-1], latest_pos/1000),\n xytext=(10, 0), textcoords='offset points',\n color=COLORS['net_pos_line'], fontsize=11, fontweight='bold', va='center')\n\n # X 軸設定(每 4 週一個標籤 + 確保最後一週,1月顯示年份,其他月只顯示月份)\n tick_positions = list(x[::4])\n # 確保最後一週也有標籤\n if x[-1] not in tick_positions:\n tick_positions.append(x[-1])\n\n tick_labels = []\n for i in tick_positions:\n d = dates[i]\n if hasattr(d, 'month'):\n # 1月顯示完整年月,其他月只顯示月份數字\n if d.month == 1:\n tick_labels.append(d.strftime('%Y-%m'))\n else:\n tick_labels.append(str(d.month))\n else:\n tick_labels.append(str(d)[:7])\n ax1.set_xticks(tick_positions)\n ax1.set_xticklabels(tick_labels, rotation=0, fontsize=9)\n\n ax1.set_ylabel('週流量 (合約)', color=COLORS['text'], fontsize=10)\n ax1.yaxis.set_major_formatter(FuncFormatter(format_contracts))\n ax1.set_title('分組週流量 + 總淨部位', fontsize=11, color=COLORS['text'], pad=10)\n\n # 圖例\n handles = [Patch(facecolor=COLORS[g], label=GROUP_LABELS[g], alpha=0.85) for g in ALL_GROUPS]\n handles.append(plt.Line2D([0], [0], color=COLORS['net_pos_line'], linewidth=2.5, label='總淨部位(右軸)'))\n ax1.legend(handles=handles, loc='upper left', fontsize=8, ncol=4,\n facecolor=COLORS['background'], edgecolor=COLORS['grid'])\n\n ax1.grid(True, color=COLORS['grid'], alpha=0.3, linewidth=0.5)\n ax1.set_axisbelow(True)\n\n # ========== 添加 USDA 關鍵事件標註 ==========\n y_min, y_max = ax1.get_ylim()\n add_usda_event_annotations(ax1, dates, y_min, y_max)\n\n # ========== 圖 2: 火力熱圖時序 ==========\n ax2 = fig.add_subplot(gs[1, :3])\n ax2.set_facecolor(COLORS['background'])\n\n # 準備熱圖數據(使用指定排序)\n fp_data = firepower_df[FIREPOWER_ORDER].T.values # groups x weeks\n fp_groups = [GROUP_LABELS[g] for g in FIREPOWER_ORDER]\n\n # 自定義顏色映射(低→高 = 紅→橙→綠)\n fp_cmap = LinearSegmentedColormap.from_list(\n 'firepower',\n [COLORS['firepower_low'], COLORS['firepower_mid'], COLORS['firepower_high']]\n )\n\n im = ax2.imshow(fp_data, aspect='auto', cmap=fp_cmap, vmin=0, vmax=1)\n\n # Y 軸:群組名稱\n ax2.set_yticks(np.arange(len(fp_groups)))\n ax2.set_yticklabels(fp_groups, fontsize=9)\n\n # X 軸:日期(每 4 週一個標籤 + 確保最後一週,1月顯示年份,其他月只顯示月份)\n x_ticks = list(np.arange(0, len(dates), 4))\n # 確保最後一週也有標籤\n if len(dates) - 1 not in x_ticks:\n x_ticks.append(len(dates) - 1)\n\n # 生成標籤\n tick_labels = []\n for i in x_ticks:\n d = dates[i]\n if hasattr(d, 'month'):\n # 1月顯示完整年月,其他月只顯示月份數字\n if d.month == 1:\n tick_labels.append(d.strftime('%Y-%m'))\n else:\n tick_labels.append(str(d.month))\n else:\n tick_labels.append(str(d)[:7])\n ax2.set_xticks(x_ticks)\n ax2.set_xticklabels(tick_labels, rotation=0, fontsize=9)\n\n ax2.set_title('火力分數時序圖', fontsize=11, color=COLORS['text'], pad=10)\n\n # 色條\n cbar = fig.colorbar(im, ax=ax2, orientation='vertical', shrink=0.8, pad=0.02)\n cbar.set_label('火力 (高=淨賣出部位高=未來買回潛力大)', fontsize=9, color=COLORS['text'])\n cbar.ax.tick_params(labelcolor=COLORS['text_dim'])\n\n # 標註最新火力值\n for i, g in enumerate(FIREPOWER_ORDER):\n fp_val = firepower_df[g].iloc[-1]\n if pd.notna(fp_val):\n ax2.text(len(dates)-1 + 0.5, i, f'{fp_val:.0%}',\n va='center', ha='left', fontsize=9, fontweight='bold',\n color=COLORS['text'])\n\n # ========== 右側資訊面板 ==========\n ax_info = fig.add_subplot(gs[:, 3])\n ax_info.set_facecolor(COLORS['background'])\n ax_info.axis('off')\n\n # 資訊文字\n info_text = []\n info_text.append(f\"━━━ 最新週摘要 ━━━\")\n info_text.append(f\"最新報告日: {latest_summary.get('date', 'N/A')}\")\n info_text.append(\"\")\n\n # 訊號\n call = latest_summary.get('call', 'N/A')\n confidence = latest_summary.get('confidence', 0)\n info_text.append(f\"訊號: {call}\")\n info_text.append(f\"信心: {confidence:.0%}\")\n info_text.append(\"\")\n\n # 總體指標\n info_text.append(\"━━━ 總體指標 ━━━\")\n total_flow = latest_summary.get('total_flow')\n total_pos = latest_summary.get('total_net_pos')\n total_fp = latest_summary.get('total_firepower')\n\n if total_flow is not None:\n info_text.append(f\"週流量: {total_flow:+,}\")\n if total_pos is not None:\n info_text.append(f\"淨部位: {total_pos:,}\")\n if total_fp is not None:\n info_text.append(f\"火力: {total_fp:.0%}\")\n info_text.append(\"\")\n\n # 分組流量(使用中文群組名)\n info_text.append(\"━━━ 分組流量 ━━━\")\n by_group = latest_summary.get('by_group', {})\n for g in ALL_GROUPS:\n if g in by_group:\n flow = by_group[g].get('flow')\n if flow is not None:\n label = GROUP_LABELS.get(g, g)\n info_text.append(f\"{label:6}: {flow:+,}\")\n info_text.append(\"\")\n\n # 風險提示\n risks = latest_summary.get('risks', [])\n if risks:\n info_text.append(\"━━━ 風險提示 ━━━\")\n for r in risks[:3]:\n info_text.append(f\"• {r[:20]}\")\n\n # 繪製文字\n y_pos = 0.95\n for line in info_text:\n if '━━━' in line:\n color = COLORS['text']\n fontweight = 'bold'\n fontsize = 10\n elif line.startswith('訊號:'):\n color = COLORS['bullish'] if '買進' in call else COLORS['bearish'] if '賣出' in call else COLORS['text']\n fontweight = 'bold'\n fontsize = 10\n else:\n color = COLORS['text_dim']\n fontweight = 'normal'\n fontsize = 9\n\n ax_info.text(0.05, y_pos, line, transform=ax_info.transAxes,\n fontsize=fontsize, fontweight=fontweight, color=color,\n verticalalignment='top')\n y_pos -= 0.045\n\n # ========== 標題 ==========\n fig.suptitle(title, color=COLORS['text'], fontsize=14, fontweight='bold', y=0.98)\n\n # ========== 頁尾 ==========\n fig.text(0.02, 0.01, \"資料來源: CFTC CoT\",\n color=COLORS['text_dim'], fontsize=8, ha='left')\n fig.text(0.98, 0.01, f'生成時間: {datetime.now().strftime(\"%Y-%m-%d %H:%M\")}',\n color=COLORS['text_dim'], fontsize=8, ha='right')\n\n # ========== 輸出 ==========\n plt.tight_layout()\n plt.subplots_adjust(top=0.93, bottom=0.05)\n\n if output_path:\n output_path = Path(output_path)\n output_path.parent.mkdir(parents=True, exist_ok=True)\n plt.savefig(output_path, dpi=150, facecolor=COLORS['background'],\n edgecolor='none', bbox_inches='tight')\n print(f\"[Chart] 已保存到: {output_path}\")\n else:\n plt.show()\n\n plt.close()\n\n\ndef main():\n parser = argparse.ArgumentParser(\n description=\"生成農產品對沖基金部位視覺化圖表(Bloomberg 風格)\"\n )\n parser.add_argument(\n \"--output\", \"-o\",\n type=str,\n default=None,\n help=\"輸出路徑(預設: output/agri_fund_positioning_YYYY-MM-DD.png)\"\n )\n parser.add_argument(\n \"--weeks\", \"-w\",\n type=int,\n default=52,\n help=\"顯示週數(預設: 52)\"\n )\n parser.add_argument(\n \"--start\",\n type=str,\n default=\"2023-01-01\",\n help=\"資料起始日期(預設: 2023-01-01)\"\n )\n\n args = parser.parse_args()\n\n try:\n print(\"\\n\" + \"=\" * 60)\n print(\"農產品對沖基金部位視覺化\")\n print(\"=\" * 60 + \"\\n\")\n\n # 抓取資料\n print(\"正在抓取 CFTC COT 資料...\")\n raw_df = fetch_cot_from_api(args.start, datetime.now().strftime(\"%Y-%m-%d\"))\n\n if raw_df.empty:\n print(\"錯誤: 無法抓取資料\")\n return 1\n\n # 解析與計算\n cot_df = parse_cot_data(raw_df)\n cot_df = calculate_flows(cot_df)\n flows_df, positions_df = aggregate_by_group(cot_df)\n\n print(f\"資料範圍: {flows_df.index.min()} 至 {flows_df.index.max()}\")\n print(f\"週數: {len(flows_df)}\")\n\n # 計算火力時序\n print(\"正在計算火力分數...\")\n firepower_df = calculate_firepower_series(positions_df)\n\n # 準備最新摘要\n latest_date = flows_df.index.max()\n latest_flow = flows_df.loc[latest_date]\n latest_pos = positions_df.loc[latest_date]\n latest_fp = firepower_df.loc[latest_date]\n\n # 判斷訊號(純中文)\n total_flow = latest_flow['total']\n total_fp = latest_fp['total'] if pd.notna(latest_fp['total']) else None\n\n if total_flow > 0:\n call = \"基金買進\"\n elif total_flow \u003c 0:\n call = \"基金賣出\"\n else:\n call = \"中性\"\n\n if total_fp and total_fp > 0.85:\n call += \"(極端空頭)\"\n elif total_fp and total_fp \u003c 0.2:\n call += \"(擁擠)\"\n\n confidence = 0.7\n if total_fp and total_fp > 0.8:\n confidence += 0.1\n if abs(total_flow) > 30000:\n confidence += 0.1\n\n latest_summary = {\n \"date\": str(latest_date),\n \"call\": call,\n \"confidence\": min(confidence, 0.95),\n \"total_flow\": int(total_flow),\n \"total_net_pos\": int(latest_pos['total']),\n \"total_firepower\": total_fp,\n \"by_group\": {\n g: {\n \"flow\": int(latest_flow[g]) if pd.notna(latest_flow[g]) else None,\n \"net_pos\": int(latest_pos[g]) if pd.notna(latest_pos[g]) else None,\n \"firepower\": latest_fp[g] if pd.notna(latest_fp[g]) else None,\n }\n for g in ALL_GROUPS\n },\n \"risks\": [\"COT 資料只到週二\"],\n }\n\n # 決定輸出路徑\n if args.output:\n output_path = args.output\n else:\n today = datetime.now().strftime('%Y-%m-%d')\n # 找到專案根目錄\n current_dir = Path(__file__).resolve().parent\n root_dir = current_dir\n for _ in range(5):\n if (root_dir / 'output').exists() or root_dir.name == 'macro-skills':\n break\n root_dir = root_dir.parent\n\n output_path = root_dir / 'output' / f'agri_fund_positioning_{today}.png'\n\n # 生成圖表\n print(f\"\\n正在生成圖表...\")\n create_positioning_chart(\n flows_df, positions_df, firepower_df,\n latest_summary,\n output_path=str(output_path),\n weeks_to_show=args.weeks,\n )\n\n print(\"\\n完成!\")\n return 0\n\n except Exception as e:\n print(f\"\\n[Error] {e}\")\n import traceback\n traceback.print_exc()\n return 1\n\n\nif __name__ == \"__main__\":\n import sys\n sys.exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":23775,"content_sha256":"afac79b820b1bd679d0e4f8f111a0193a8f54e07b64002260edf9151886d0732"},{"filename":"skill.yaml","content":"displayName: 追蹤農產品對沖基金部位\nemoji: \"\\U0001F33E\"\nauthorUrl: https://github.com/fatfingererr/macro-skills\n\ntools:\n - claude-code\n\nfeatured: false\ninstallCount: 0\n\ntestQuestions:\n - question: '分析最新一週的農產品對沖基金部位變化'\n imagePath: images/agri-fund-positioning-2026-01-27.png\n expectedResult: |\n 農產品對沖基金部位分析報告\n\n 資料截止日: 2026-01-20 (COT 週報)\n 資料來源: CFTC Socrata API\n\n 主要訊號\n ┌────────────────────────────────────┬────────────────────┐\n │ 訊號 │ 說明 │\n ├────────────────────────────────────┼────────────────────┤\n │ Funds continue selling │ 基金持續賣出 │\n ├────────────────────────────────────┼────────────────────┤\n │ Extreme short - watch for reversal │ 極端空頭,留意反轉 │\n ├────────────────────────────────────┼────────────────────┤\n │ Macro mood bullish │ 宏觀環境有利 │\n └────────────────────────────────────┴────────────────────┘\n 信心度: 90%\n\n 最新週流量變化\n ┌──────────┬─────────────┬───────────────┬──────┐\n │ 群組 │ 流量 (合約) │ 淨部位 (合約) │ 火力 │\n ├──────────┼─────────────┼───────────────┼──────┤\n │ grains │ -31,279 │ -171,393 │ 58% │\n ├──────────┼─────────────┼───────────────┼──────┤\n │ oilseeds │ +11,517 │ -43,645 │ 62% │\n ├──────────┼─────────────┼───────────────┼──────┤\n │ meats │ +18,972 │ +153,388 │ 31% │\n ├──────────┼─────────────┼───────────────┼──────┤\n │ softs │ -23,887 │ -165,987 │ 99% │\n ├──────────┼─────────────┼───────────────┼──────┤\n │ fiber │ +1,607 │ -25,824 │ 58% │\n ├──────────┼─────────────┼───────────────┼──────┤\n │ dairy │ -1,489 │ -29,799 │ 99% │\n ├──────────┼─────────────┼───────────────┼──────┤\n │ 總計 │ -24,559 │ -283,260 │ 86% │\n └──────────┴─────────────┴───────────────┴──────┘\n\n 關鍵解讀\n 1. 總體: 基金整體淨空頭 -28.3 萬合約,本週續流出 -2.5 萬\n 2. 極端空頭訊號: 火力 86% 表示部位處於過去 3 年的第 86 百分位低點,反轉潛力高\n 3. 分化明顯:\n - 穀物 (grains) 與軟性商品 (softs) 持續被拋售\n - 肉類 (meats) 與油籽 (oilseeds) 出現回補\n 4. 宏觀順風: USD 走弱、原油/金屬走強,有利於商品價格\n\n 風險提示\n - COT 資料截至週二,Wed-Fri 尚需驗證\n - 極端部位可能觸發軋空行情\n\n - question: '基金火力在穀物板塊還有多少空間?'\n expectedResult: |\n 穀物板塊基金火力分析\n \n 核心答案:穀物火力 58%,仍有中等加碼空間 \n ┌──────────────────┬──────────┬────────────────────────────┐\n │ 板塊 │ 火力分數 │ 解讀 │\n ├──────────────────┼──────────┼────────────────────────────┤ \n │ Grains(穀物) │ 58% │ 中性偏高,仍有空間但非極端 │\n ├──────────────────┼──────────┼────────────────────────────┤\n │ Oilseeds(油籽) │ 62% │ 類似穀物,中等空間 │\n ├──────────────────┼──────────┼────────────────────────────┤\n │ Meats(肉類) │ 31% │ 偏擁擠,空間有限 │\n ├──────────────────┼──────────┼────────────────────────────┤\n │ Softs(軟商品) │ 99% │ 極端空頭,最大反彈潛力 │\n ├──────────────────┼──────────┼────────────────────────────┤\n │ Fiber(棉花) │ 58% │ 中性 │\n ├──────────────────┼──────────┼────────────────────────────┤\n │ Dairy(乳製品) │ 99% │ 極端空頭 │\n └──────────────────┴──────────┴────────────────────────────┘\n \n 穀物板塊詳情\n 最新一週流量:-31,279 合約(仍在賣出)\n\n 火力 58% 的含義:\n - 基金目前淨部位處於過去 156 週的 42 分位(偏空)\n - 距離歷史極端多頭(0% 火力)還有相當距離\n - 如果出現利多催化劑(出口需求、天氣風險),基金有空間轉買\n \n 可交易觀點\n 穀物板塊:觀望轉多\n - 火力充足(58%),但尚未見到買盤回歸訊號\n - 宏觀順風(67%)支持風險資產\n - 等待 COT 週流量轉正作為確認\n \n 風險提示\n - COT 資料截止週二,週三至週五為推估\n - 下週 USDA 報告可能改變敘事\n\n - question: '驗證新聞敘事:基金週中買回是否有宏觀支持?'\n expectedResult: |\n 週中買回敘事驗證結果\n \n 農產品價格動能(Wed-Fri)\n ┌───────────────┬────────┬─────────┬──────────┐\n │ 商品 │ 週報酬 │ Wed-Fri │ 買盤訊號 │ \n ├───────────────┼────────┼─────────┼──────────┤ ⧉ \n │ DBA 農產品ETF │ +1.06% │ +0.62% │ ✓ │\n ├───────────────┼────────┼─────────┼──────────┤\n │ 玉米期貨 │ +1.06% │ +1.00% │ ✓ │\n ├───────────────┼────────┼─────────┼──────────┤\n │ 大豆期貨 │ +0.71% │ -0.33% │ ✗ │\n ├───────────────┼────────┼─────────┼──────────┤\n │ 小麥期貨 │ +2.16% │ +1.12% │ ✓ │\n └───────────────┴────────┴─────────┴──────────┘\n 農產品動能評分:3/4 支持(75%)\n\n ---\n 宏觀順風驗證(Wed-Fri)\n ┌─────────────┬────────┬─────────┬────────────────┐\n │ 指標 │ 週報酬 │ Wed-Fri │ 順風 │\n ├─────────────┼────────┼─────────┼────────────────┤\n │ 美元 (UUP) │ -1.58% │ -1.36% │ ✓ 走弱利於商品 │\n ├─────────────┼────────┼─────────┼────────────────┤\n │ 原油 (CL=F) │ -0.10% │ +1.55% │ ✓ 風險偏好回升 │\n ├─────────────┼────────┼─────────┼────────────────┤\n │ 金屬 (XME) │ +0.30% │ -3.46% │ ✗ 不支持 │\n └─────────────┴────────┴─────────┴────────────────┘\n 宏觀順風評分:2/3 支持(67%)\n\n ---\n 驗證結論\n\n 敘事:「基金週中買回」\n 驗證結果:部分支持 ⚠️\n\n 支持證據:\n ✓ 玉米、小麥週中價格走強(+1.0%, +1.1%)\n ✓ 美元大幅走弱(-1.36%),利於商品買盤\n ✓ 原油反彈(+1.55%),風險情緒改善\n\n 不支持證據:\n ✗ 大豆週中下跌(-0.33%),與敘事矛盾\n ✗ 金屬大跌(-3.46%),工業需求訊號弱\n ✗ COT 最新數據仍顯示賣出(-31,279 合約)\n\n 綜合判斷:\n 宏觀環境確實有利於基金買回(美元弱+油價強),\n 但 COT 數據尚未確認轉向。目前更像是「空頭回補」\n 而非「新建多頭」。等待下週五 COT 確認。\n\n 下一步監控重點\n 1. 本週五 COT 更新:確認穀物流量是否轉正\n 2. 大豆表現:若大豆補漲,則敘事更可信\n 3. 金屬走勢:若金屬止跌,宏觀順風增強至 100%\n\nqualityScore:\n overall: 45\n badge: 中級\n evaluatedAt: \"2026-01-27\"\n\n metrics:\n problemFit: 60\n correctness: 45\n dataGovernance: 50\n robustness: 35\n maintainability: 45\n usability: 45\n\n metricDetails:\n problemFit:\n score: 60\n strengths:\n - 清晰的問題定義:量化新聞敘事\n - 涵蓋 COT + 宏觀 + 基本面整合\n - 分組彙總邏輯完整\n improvements:\n - Alpha 階段,功能未完善\n - 週中回補驗證需更多代理資料\n\n correctness:\n score: 45\n strengths:\n - 方法論有明確的公式定義\n - 火力計算邏輯可重現\n improvements:\n - COT 資料解析需驗證\n - 缺少 golden case 範例\n\n dataGovernance:\n score: 50\n strengths:\n - 使用 CFTC 官方公開資料\n - FRED/Yahoo 無需 API key\n improvements:\n - COT CSV 格式可能變化\n - 缺少 fallback 來源\n\n robustness:\n score: 35\n strengths:\n - 有基本的分組容錯\n improvements:\n - Alpha 階段穩定性不足\n - 缺少 failure-modes.md\n - 缺值處理未完善\n\n maintainability:\n score: 45\n strengths:\n - 工作流程分離設計\n - 參數集中定義\n improvements:\n - 需增加版本控制\n - 合約對照表需定期更新\n\n usability:\n score: 45\n strengths:\n - 輸出包含可交易呼叫\n - 有信心水準與風險提示\n improvements:\n - 缺少歷史對照\n - 視覺化範例不足\n\n details: |\n **任務適配度(60/100)**\n - 問題定義清晰\n - 待改進:Alpha 階段未完善\n\n **正確性(45/100)**\n - 公式可重現\n - 待改進:缺少 golden case\n\n **資料治理(50/100)**\n - 使用公開資料\n - 待改進:COT 格式風險\n\n **穩健性(35/100)**\n - 有基本容錯\n - 待改進:Alpha 穩定性\n\n **可維護性(45/100)**\n - 工作流程分離\n - 待改進:合約表更新\n\n **輸出可用性(45/100)**\n - 有可交易呼叫\n - 待改進:歷史對照\n\n upgradeNotes:\n targetBadge: 中高級\n requirements:\n - metric: robustness\n currentScore: 35\n targetScore: 55\n suggestion: 完成 Alpha 測試與 failure-modes.md\n - metric: correctness\n currentScore: 45\n targetScore: 65\n suggestion: 增加 golden case 與回歸測試\n - metric: usability\n currentScore: 45\n targetScore: 60\n suggestion: 增加歷史事件對照\n\nbestPractices:\n - title: 週五 COT 發布後再執行\n description: CFTC COT 報告在週五下午 3:30 ET 發布,確認發布後再抓取最新資料\n - title: 對照多期資料判斷趨勢\n description: 單週流量可能有雜訊,建議看 2-4 週的流量動能\n - title: 結合基本面事件解讀\n description: 大幅流入/流出通常有對應的 USDA 報告或出口數據\n - title: 注意火力極端值\n description: 火力低於 0.2 時要警惕擁擠風險,高於 0.8 時留意反轉機會\n\npitfalls:\n - title: 將 COT 當成即時資料\n description: COT 資料截止到週二,週三~週五的部位變化只能用代理推估\n consequence: 可能誤判週中反轉\n - title: 忽略合約規格差異\n description: 不同商品的合約大小與單位不同(bushels vs cwt vs lbs)\n consequence: 跨商品比較失真\n - title: 單純看淨部位忽略結構\n description: 相同淨部位下,多空結構不同(集中 vs 分散)風險也不同\n consequence: 低估部位擠壓風險\n\nfaq:\n - question: COT 報告有哪些版本?\n answer: |\n CFTC 發布多種 COT 報告:\n\n **Legacy COT**\n - 分類:Commercial / Non-Commercial / Non-Reportable\n - 最常用,歷史最長\n\n **Disaggregated COT**\n - 分類更細:Producer/Merchant, Swap Dealer, Managed Money, Other\n - 2009 年後可用\n\n **Traders in Financial Futures (TFF)**\n - 金融期貨專用\n - 分類:Dealer, Asset Manager, Leveraged, Other\n\n - question: 如何定義「基金」部位?\n answer: |\n 本技能預設使用 Legacy COT 的 Non-Commercial(非商業)部位:\n - 代表投機性質的交易者\n - 包含對沖基金、CTA、個人大戶\n - 是市場情緒的代理指標\n\n 若用 Disaggregated COT,可聚焦 Managed Money。\n\n - question: 火力分數如何解讀?\n answer: |\n | 火力區間 | 意義 | 建議行動 |\n |------------|------------------------------|----------------------|\n | 0.8 - 1.0 | 極低部位,大量加碼空間 | 留意反轉做多機會 |\n | 0.6 - 0.8 | 偏低部位,仍有上行空間 | 順勢做多相對安全 |\n | 0.4 - 0.6 | 中性部位 | 觀望為主 |\n | 0.2 - 0.4 | 偏高部位,空間有限 | 謹慎追多 |\n | 0.0 - 0.2 | 極高部位,擁擠風險高 | 警惕反轉,考慮減碼 |\n\nabout:\n repository: https://github.com/fatfingererr/macro-skills\n branch: main\n additionalInfo: |\n ## 資料來源\n\n **CFTC Commitments of Traders**\n - 官網:https://www.cftc.gov/MarketReports/CommitmentsofTraders/index.htm\n - 更新:每週五下午 3:30 ET\n - 格式:CSV/TXT\n - 費用:免費公開\n\n **宏觀指標**\n - 美元:FRED DXY proxy 或 Yahoo Finance UUP\n - 原油:Yahoo Finance CL=F 或 USO\n - 金屬:Yahoo Finance XME 或 FRED 工業金屬指數\n\n ## 理論背景\n\n 本技能基於 COT 分析的經典方法論:\n - 非商業部位代表投機情緒\n - 極端部位通常是反轉訊號\n - 資金流向可驗證敘事一致性\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":16972,"content_sha256":"c6bbc738767c88fc3e4f6f473a539dc04d9270e87d4fc2b6142048bf7e8c8ff2"},{"filename":"templates/annotations.md","content":"# 圖表標註規則對照表\n\n## 1. 標註規則定義\n\n將圖表上的敘事標註轉為可重複驗證的規則:\n\n### 1.1 基本面驅動標註\n\n| 標註 ID | 顯示文字 | 觸發條件 |\n|----------------------|--------------------|--------------------------------------------|\n| `strong_corn_demand` | Strong Corn Demand | corn_export_surprise > 0 AND grains_flow > 0 |\n| `strong_soy_demand` | Strong Soy Demand | soy_export_surprise > 0 AND oilseeds_flow > 0 |\n| `bearish_usda_stats` | Bearish USDA Stats | wasde_surprise \u003c 0 AND grains_flow \u003c 0 |\n| `bullish_usda_stats` | Bullish USDA Stats | wasde_surprise > 0 AND grains_flow > 0 |\n| `weather_premium` | Weather Premium | weather_concern = true AND flow > 0 |\n\n### 1.2 宏觀驅動標註\n\n| 標註 ID | 顯示文字 | 觸發條件 |\n|----------------------|--------------------|--------------------------------------------|\n| `macro_mood_bullish` | Macro Mood Bullish | macro_tailwind_score >= 0.67 |\n| `macro_headwind` | Macro Headwind | macro_tailwind_score \u003c= 0.33 |\n| `usd_tailwind` | USD Tailwind | usd_weekly_return \u003c -0.5% |\n| `risk_on_mode` | Risk-On Mode | spy_return > 1% AND vix_down |\n\n### 1.3 流量特徵標註\n\n| 標註 ID | 顯示文字 | 觸發條件 |\n|----------------------|--------------------|--------------------------------------------|\n| `funds_back_buying` | Funds Back & Buying| flow_reversal = positive AND firepower > 0.5 |\n| `fund_capitulation` | Fund Capitulation | flow \u003c p5_historical AND firepower > 0.8 |\n| `crowded_long` | Crowded Long | firepower \u003c 0.2 |\n| `extreme_short` | Extreme Short | firepower > 0.85 |\n| `small_holiday_flows`| Small Holiday Flows| abs(total_flow) \u003c p25_historical |\n\n### 1.4 群組動態標註\n\n| 標註 ID | 顯示文字 | 觸發條件 |\n|-----------------------|---------------------|--------------------------------------------|\n| `grains_momentum_up` | Grains Momentum Up | grains_flow > 0 for 2+ weeks |\n| `oilseeds_outflow` | Oilseeds Outflow | oilseeds_flow \u003c 0 for 2+ weeks |\n| `meats_rotation` | Meats Rotation | meats_flow direction changed |\n| `broad_based_buying` | Broad-Based Buying | 3+ groups with positive flow |\n| `sector_divergence` | Sector Divergence | grains and oilseeds flow opposite signs |\n\n---\n\n## 2. 規則實作\n\n```python\nANNOTATION_RULES = {\n # 基本面驅動\n \"strong_corn_demand\": {\n \"label\": \"Strong Corn Demand\",\n \"condition\": lambda ctx: (\n ctx.get(\"corn_export_surprise\", 0) > 0 and\n ctx.get(\"grains_flow\", 0) > 0\n ),\n \"evidence_fn\": lambda ctx: [\n f\"Corn export surprise: +{ctx.get('corn_export_surprise', 0):.1%}\",\n f\"Grains flow: {ctx.get('grains_flow', 0):+,} contracts\"\n ],\n \"priority\": 2\n },\n\n \"bearish_usda_stats\": {\n \"label\": \"Bearish USDA Stats\",\n \"condition\": lambda ctx: (\n ctx.get(\"wasde_surprise\", 0) \u003c 0 and\n ctx.get(\"grains_flow\", 0) \u003c 0\n ),\n \"evidence_fn\": lambda ctx: [\n f\"WASDE surprise: {ctx.get('wasde_surprise', 0):+.1%}\",\n f\"Grains outflow: {ctx.get('grains_flow', 0):,} contracts\"\n ],\n \"priority\": 2\n },\n\n # 宏觀驅動\n \"macro_mood_bullish\": {\n \"label\": \"Macro Mood Bullish\",\n \"condition\": lambda ctx: ctx.get(\"macro_tailwind_score\", 0) >= 0.67,\n \"evidence_fn\": lambda ctx: [\n f\"Macro tailwind: {ctx.get('macro_tailwind_score', 0):.0%}\",\n *[k for k, v in ctx.get(\"macro_components\", {}).items() if v]\n ],\n \"priority\": 1\n },\n\n \"macro_headwind\": {\n \"label\": \"Macro Headwind\",\n \"condition\": lambda ctx: ctx.get(\"macro_tailwind_score\", 0) \u003c= 0.33,\n \"evidence_fn\": lambda ctx: [\n f\"Macro tailwind: {ctx.get('macro_tailwind_score', 0):.0%}\",\n \"USD strong\" if not ctx.get(\"macro_components\", {}).get(\"usd_down\") else None,\n \"Oil weak\" if not ctx.get(\"macro_components\", {}).get(\"crude_up\") else None\n ],\n \"priority\": 1\n },\n\n # 流量特徵\n \"funds_back_buying\": {\n \"label\": \"Funds Back & Buying\",\n \"condition\": lambda ctx: (\n ctx.get(\"flow_reversal\") == \"positive\" and\n ctx.get(\"firepower_total\", 0) > 0.5\n ),\n \"evidence_fn\": lambda ctx: [\n \"Flow reversed to positive\",\n f\"Firepower: {ctx.get('firepower_total', 0):.0%}\"\n ],\n \"priority\": 1\n },\n\n \"crowded_long\": {\n \"label\": \"Crowded Long\",\n \"condition\": lambda ctx: ctx.get(\"firepower_total\", 1) \u003c 0.2,\n \"evidence_fn\": lambda ctx: [\n f\"Firepower critically low: {ctx.get('firepower_total', 0):.0%}\",\n \"Position near historical high\"\n ],\n \"priority\": 1\n },\n\n \"small_holiday_flows\": {\n \"label\": \"Small Holiday Flows\",\n \"condition\": lambda ctx: (\n abs(ctx.get(\"total_flow\", 0)) \u003c ctx.get(\"flow_p25\", float(\"inf\"))\n ),\n \"evidence_fn\": lambda ctx: [\n f\"Flow: {ctx.get('total_flow', 0):,} (below 25th percentile)\",\n \"Likely holiday/thin liquidity\"\n ],\n \"priority\": 3\n },\n\n # 群組動態\n \"broad_based_buying\": {\n \"label\": \"Broad-Based Buying\",\n \"condition\": lambda ctx: (\n sum(1 for g in [\"grains\", \"oilseeds\", \"meats\", \"softs\"]\n if ctx.get(f\"{g}_flow\", 0) > 0) >= 3\n ),\n \"evidence_fn\": lambda ctx: [\n f\"{g.capitalize()}: +{ctx.get(f'{g}_flow', 0):,}\"\n for g in [\"grains\", \"oilseeds\", \"meats\", \"softs\"]\n if ctx.get(f\"{g}_flow\", 0) > 0\n ],\n \"priority\": 2\n }\n}\n```\n\n---\n\n## 3. 標註生成函數\n\n```python\ndef generate_annotations(context: dict) -> list:\n \"\"\"\n 根據上下文生成所有觸發的標註\n\n Parameters:\n -----------\n context : dict\n 包含所有指標的上下文字典\n\n Returns:\n --------\n list\n 觸發的標註清單\n \"\"\"\n annotations = []\n\n for rule_id, rule in ANNOTATION_RULES.items():\n try:\n if rule[\"condition\"](context):\n evidence = rule[\"evidence_fn\"](context)\n # 過濾 None 值\n evidence = [e for e in evidence if e is not None]\n\n annotations.append({\n \"label\": rule_id,\n \"display\": rule[\"label\"],\n \"rule_hit\": True,\n \"evidence\": evidence,\n \"priority\": rule.get(\"priority\", 2),\n \"date\": context.get(\"date\")\n })\n except Exception as e:\n # 規則執行失敗時跳過\n continue\n\n # 按優先級排序(1 最高)\n annotations.sort(key=lambda x: x[\"priority\"])\n\n return annotations\n```\n\n---\n\n## 4. 標註優先級\n\n| 優先級 | 說明 | 範例 |\n|--------|----------------------|--------------------------------|\n| 1 | 核心訊號 | Funds Back & Buying, Crowded |\n| 2 | 重要驅動 | Strong Demand, USDA Stats |\n| 3 | 輔助資訊 | Small Holiday Flows |\n\n---\n\n## 5. 標註顯示樣式\n\n### 5.1 圖表標註\n\n```python\nANNOTATION_STYLES = {\n \"funds_back_buying\": {\"color\": \"green\", \"marker\": \"^\", \"size\": 12},\n \"fund_capitulation\": {\"color\": \"darkgreen\", \"marker\": \"^\", \"size\": 14},\n \"crowded_long\": {\"color\": \"red\", \"marker\": \"v\", \"size\": 12},\n \"extreme_short\": {\"color\": \"darkred\", \"marker\": \"v\", \"size\": 14},\n \"macro_mood_bullish\": {\"color\": \"blue\", \"marker\": \"o\", \"size\": 10},\n \"macro_headwind\": {\"color\": \"orange\", \"marker\": \"o\", \"size\": 10},\n \"strong_corn_demand\": {\"color\": \"gold\", \"marker\": \"s\", \"size\": 8},\n \"bearish_usda_stats\": {\"color\": \"brown\", \"marker\": \"s\", \"size\": 8},\n \"small_holiday_flows\": {\"color\": \"gray\", \"marker\": \".\", \"size\": 6}\n}\n```\n\n### 5.2 Markdown 標註\n\n```python\ndef format_annotation_markdown(ann: dict) -> str:\n \"\"\"格式化標註為 Markdown\"\"\"\n emoji_map = {\n \"funds_back_buying\": \"🟢\",\n \"crowded_long\": \"🔴\",\n \"macro_mood_bullish\": \"🔵\",\n \"strong_corn_demand\": \"🌽\",\n \"bearish_usda_stats\": \"📉\",\n \"small_holiday_flows\": \"🏖️\"\n }\n\n emoji = emoji_map.get(ann[\"label\"], \"📌\")\n evidence_str = \", \".join(ann[\"evidence\"])\n\n return f\"{emoji} **{ann['display']}**: {evidence_str}\"\n```\n\n---\n\n## 6. 使用範例\n\n```python\n# 建立上下文\ncontext = {\n \"date\": \"2026-01-21\",\n \"total_flow\": 65000,\n \"grains_flow\": 35000,\n \"oilseeds_flow\": 25000,\n \"meats_flow\": 5000,\n \"softs_flow\": 0,\n \"firepower_total\": 0.63,\n \"macro_tailwind_score\": 0.67,\n \"macro_components\": {\n \"usd_down\": True,\n \"crude_up\": True,\n \"metals_up\": False\n },\n \"corn_export_surprise\": 0.05,\n \"flow_reversal\": \"positive\",\n \"flow_p25\": 20000\n}\n\n# 生成標註\nannotations = generate_annotations(context)\n\n# 輸出\nfor ann in annotations:\n print(f\"[{ann['priority']}] {ann['display']}: {ann['evidence']}\")\n```\n\n輸出:\n```\n[1] Funds Back & Buying: ['Flow reversed to positive', 'Firepower: 63%']\n[1] Macro Mood Bullish: ['Macro tailwind: 67%', 'usd_down', 'crude_up']\n[2] Strong Corn Demand: ['Corn export surprise: +5.0%', 'Grains flow: +35,000 contracts']\n[2] Broad-Based Buying: ['Grains: +35,000', 'Oilseeds: +25,000', 'Meats: +5,000']\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9964,"content_sha256":"0bc79d5d9dec608898b92160f2b3739a6a76ebdcf2f02fe3bb8c6f0ebc4fc8fc"},{"filename":"templates/output-json.md","content":"# JSON 輸出結構定義\n\n## 完整輸出結構\n\n```json\n{\n \"skill\": \"track-agri-hedge-fund-positioning\",\n \"version\": \"0.1.0\",\n \"generated_at\": \"2026-01-27T10:30:00Z\",\n \"as_of\": \"2026-01-21\",\n\n \"summary\": {\n \"call\": \"Funds back & buying\",\n \"confidence\": 0.72,\n \"why\": [\n \"COT 週部位變化顯示農產品總流量由負轉正\",\n \"分組(穀物/油籽)同步改善,非單一品種噪音\",\n \"宏觀順風:美元走弱、原油與金屬偏強\"\n ],\n \"risks\": [\n \"COT 只到週二:Wed–Fri 的『買回』屬推估\",\n \"USDA 報告或天氣變動可能讓訊號反轉\"\n ],\n \"next_steps\": [\n \"監控週五 USDA Export Sales 報告\",\n \"觀察火力是否持續回升\"\n ]\n },\n\n \"latest_metrics\": {\n \"cot_week_end\": \"2026-01-21\",\n \"flow_total_contracts\": 58,\n \"flow_by_group_contracts\": {\n \"grains\": 35,\n \"oilseeds\": 25,\n \"meats\": 5,\n \"softs\": 0\n },\n \"net_position_by_group\": {\n \"grains\": 125000,\n \"oilseeds\": 85000,\n \"meats\": 12000,\n \"softs\": -5000,\n \"total\": 217000\n },\n \"buying_firepower\": {\n \"total\": 0.63,\n \"grains\": 0.58,\n \"oilseeds\": 0.67,\n \"meats\": 0.41,\n \"softs\": 0.75\n },\n \"macro_tailwind_score\": 0.67,\n \"macro_components\": {\n \"usd_down\": true,\n \"crude_up\": true,\n \"metals_up\": false\n }\n },\n\n \"weekly_flows\": [\n {\n \"date\": \"2026-01-21\",\n \"grains\": 35,\n \"oilseeds\": 25,\n \"meats\": 5,\n \"softs\": 0,\n \"total\": 65\n },\n {\n \"date\": \"2026-01-14\",\n \"grains\": -10,\n \"oilseeds\": 15,\n \"meats\": -5,\n \"softs\": 2,\n \"total\": 2\n }\n ],\n\n \"firepower_history\": [\n {\n \"date\": \"2026-01-21\",\n \"total\": 0.63,\n \"grains\": 0.58,\n \"oilseeds\": 0.67,\n \"meats\": 0.41,\n \"softs\": 0.75\n }\n ],\n\n \"annotations\": [\n {\n \"label\": \"macro_mood_bullish\",\n \"rule_hit\": true,\n \"evidence\": [\"USD down\", \"crude up\"],\n \"date\": \"2026-01-21\"\n },\n {\n \"label\": \"grains_momentum_up\",\n \"rule_hit\": true,\n \"evidence\": [\"Grains flow turned positive\", \"Corn export sales up\"],\n \"date\": \"2026-01-21\"\n }\n ],\n\n \"validation\": {\n \"wed_fri_buyback\": {\n \"price_momentum\": \"bullish\",\n \"volume_elevated\": true,\n \"macro_resonance\": 0.67\n },\n \"macro_alignment\": {\n \"aligned\": true,\n \"interpretation\": \"資金流入且宏觀順風,敘事一致\"\n },\n \"overall_consistency\": 0.78,\n \"confidence_adjustment\": 0.1\n },\n\n \"metadata\": {\n \"cot_report_type\": \"legacy\",\n \"trader_group\": \"noncommercial\",\n \"position_metric\": \"net\",\n \"lookback_weeks\": 156,\n \"data_sources\": {\n \"cot\": \"CFTC\",\n \"macro\": \"Yahoo Finance\",\n \"fundamentals\": \"USDA\"\n }\n }\n}\n```\n\n---\n\n## 欄位說明\n\n### 頂層欄位\n\n| 欄位 | 類型 | 說明 |\n|--------------|--------|------------------------------|\n| skill | string | 技能名稱 |\n| version | string | 技能版本 |\n| generated_at | string | 報告生成時間(ISO 8601) |\n| as_of | string | 資料截止日期 |\n\n### summary 區塊\n\n| 欄位 | 類型 | 說明 |\n|------------|----------|--------------------------------|\n| call | string | 可交易呼叫(主要結論) |\n| confidence | number | 信心水準(0-1) |\n| why | string[] | 結論依據清單 |\n| risks | string[] | 風險提示清單 |\n| next_steps | string[] | 下一步建議 |\n\n### latest_metrics 區塊\n\n| 欄位 | 類型 | 說明 |\n|-------------------------|--------|------------------------------|\n| cot_week_end | string | COT 週截止日期 |\n| flow_total_contracts | number | 總流量(合約數) |\n| flow_by_group_contracts | object | 各群組流量 |\n| net_position_by_group | object | 各群組淨部位 |\n| buying_firepower | object | 各群組火力分數 |\n| macro_tailwind_score | number | 宏觀順風評分(0-1) |\n| macro_components | object | 宏觀成分詳情 |\n\n### annotations 區塊\n\n| 欄位 | 類型 | 說明 |\n|----------|----------|------------------------------|\n| label | string | 標註名稱 |\n| rule_hit | boolean | 規則是否觸發 |\n| evidence | string[] | 觸發證據 |\n| date | string | 觸發日期 |\n\n### validation 區塊\n\n| 欄位 | 類型 | 說明 |\n|-----------------------|--------|------------------------------|\n| wed_fri_buyback | object | 週中回補驗證 |\n| macro_alignment | object | 宏觀一致性 |\n| overall_consistency | number | 整體一致性評分 |\n| confidence_adjustment | number | 信心調整值 |\n\n---\n\n## 可能的 call 值\n\n| call | 意義 |\n|-----------------------------|--------------------------------|\n| Funds back & buying | 基金回來買進 |\n| Funds selling | 基金賣出 |\n| Macro mood bullish | 宏觀情緒偏多 |\n| Macro headwind | 宏觀逆風 |\n| Crowded long - caution | 多單擁擠,謹慎 |\n| Extreme short - watch | 極端空頭,留意反彈 |\n| Mixed signals | 訊號混合 |\n| Holiday thin flows | 假日薄流量 |\n\n---\n\n## 快速輸出模式\n\n使用 `--quick` 時的簡化輸出:\n\n```json\n{\n \"cot_week_end\": \"2026-01-21\",\n \"flow_total_contracts\": 58,\n \"flow_by_group\": {\"grains\": 35, \"oilseeds\": 25, \"meats\": 5, \"softs\": 0},\n \"buying_firepower\": {\"total\": 0.63},\n \"macro_tailwind_score\": 0.67,\n \"call\": \"Funds back & buying\"\n}\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6275,"content_sha256":"af143f030a946b35c88cef657e4d5e8c28ec0c820db649a186360287e652dfc7"},{"filename":"templates/output-markdown.md","content":"# Markdown 報告模板\n\n## 模板結構\n\n```markdown\n# 農產品對沖基金部位追蹤報告\n\n> **報告日期**: {generated_at}\n> **資料截止**: {as_of}(COT 週截止日)\n\n---\n\n## TL;DR\n\n**{call}** (信心: {confidence:.0%})\n\n{why[0]}\n\n---\n\n## 最新指標\n\n### 週流量(合約數)\n\n| 群組 | 流量 | 淨部位 | 火力 |\n|----------|----------|--------------|--------|\n| 穀物 | {grains_flow:+,} | {grains_pos:,} | {grains_fp:.0%} |\n| 油籽 | {oilseeds_flow:+,} | {oilseeds_pos:,} | {oilseeds_fp:.0%} |\n| 肉類 | {meats_flow:+,} | {meats_pos:,} | {meats_fp:.0%} |\n| 軟性商品 | {softs_flow:+,} | {softs_pos:,} | {softs_fp:.0%} |\n| **總計** | **{total_flow:+,}** | **{total_pos:,}** | **{total_fp:.0%}** |\n\n### 宏觀順風\n\n**評分: {macro_score:.0%}**\n\n| 指標 | 方向 | 訊號 |\n|------|------|------|\n| 美元 | {usd_direction} | {usd_signal} |\n| 原油 | {crude_direction} | {crude_signal} |\n| 金屬 | {metals_direction} | {metals_signal} |\n\n---\n\n## 結論依據\n\n{for why in why_list}\n- {why}\n{endfor}\n\n---\n\n## 風險提示\n\n{for risk in risks}\n- ⚠️ {risk}\n{endfor}\n\n---\n\n## 下一步建議\n\n{for step in next_steps}\n1. {step}\n{endfor}\n\n---\n\n## 圖表標註\n\n{for ann in annotations}\n### {ann.label}\n- **觸發**: {ann.rule_hit}\n- **證據**: {ann.evidence}\n{endfor}\n\n---\n\n## 驗證結果\n\n### 週中回補驗證(Wed-Fri)\n\n| 項目 | 結果 |\n|------------|-------------------|\n| 價格動能 | {wed_fri_momentum} |\n| 成交量 | {wed_fri_volume} |\n| 宏觀共振 | {wed_fri_resonance:.0%} |\n\n### 敘事一致性\n\n**整體一致性: {overall_consistency:.0%}**\n\n{narrative_assessment}\n\n---\n\n## 技術細節\n\n- COT 報表類型: {cot_report_type}\n- 交易者分類: {trader_group}\n- 部位衡量: {position_metric}\n- 火力視窗: {lookback_weeks} 週\n- 資料來源: CFTC / Yahoo Finance / USDA\n\n---\n\n*本報告由 track-agri-hedge-fund-positioning v{version} 生成*\n```\n\n---\n\n## 填充範例\n\n```markdown\n# 農產品對沖基金部位追蹤報告\n\n> **報告日期**: 2026-01-27 10:30 UTC\n> **資料截止**: 2026-01-21(COT 週截止日)\n\n---\n\n## TL;DR\n\n**Funds back & buying** (信心: 72%)\n\nCOT 週部位變化顯示農產品總流量由負轉正,分組同步改善,宏觀順風。\n\n---\n\n## 最新指標\n\n### 週流量(合約數)\n\n| 群組 | 流量 | 淨部位 | 火力 |\n|----------|----------|--------------|--------|\n| 穀物 | +35,000 | 125,000 | 58% |\n| 油籽 | +25,000 | 85,000 | 67% |\n| 肉類 | +5,000 | 12,000 | 41% |\n| 軟性商品 | +0 | -5,000 | 75% |\n| **總計** | **+65,000** | **217,000** | **63%** |\n\n### 宏觀順風\n\n**評分: 67%**\n\n| 指標 | 方向 | 訊號 |\n|------|------|----------|\n| 美元 | ↓ | 利多商品 |\n| 原油 | ↑ | 風險偏好 |\n| 金屬 | → | 中性 |\n\n---\n\n## 結論依據\n\n- COT 週部位變化顯示農產品總流量由負轉正\n- 分組(穀物/油籽)同步改善,非單一品種噪音\n- 宏觀順風:美元走弱、原油與金屬偏強\n\n---\n\n## 風險提示\n\n- ⚠️ COT 只到週二:Wed–Fri 的『買回』屬推估,需要價格/未平倉等代理證據佐證\n- ⚠️ USDA 報告或天氣/南美供給變動可能讓訊號反轉\n\n---\n\n## 下一步建議\n\n1. 監控週五 USDA Export Sales 報告\n2. 觀察火力是否持續回升\n3. 若火力突破 70%,考慮減碼\n\n---\n\n## 圖表標註\n\n### macro_mood_bullish\n- **觸發**: ✓\n- **證據**: USD down, crude up\n\n### grains_momentum_up\n- **觸發**: ✓\n- **證據**: Grains flow turned positive, Corn export sales up\n\n---\n\n## 驗證結果\n\n### 週中回補驗證(Wed-Fri)\n\n| 項目 | 結果 |\n|------------|-------------------|\n| 價格動能 | 偏多 |\n| 成交量 | 正常 |\n| 宏觀共振 | 67% |\n\n### 敘事一致性\n\n**整體一致性: 78%**\n\n敘事高度一致,可信度高\n\n---\n\n## 技術細節\n\n- COT 報表類型: legacy\n- 交易者分類: noncommercial\n- 部位衡量: net\n- 火力視窗: 156 週\n- 資料來源: CFTC / Yahoo Finance / USDA\n\n---\n\n*本報告由 track-agri-hedge-fund-positioning v0.1.0 生成*\n```\n\n---\n\n## Python 生成函數\n\n```python\ndef generate_markdown_report(result: dict) -> str:\n \"\"\"生成 Markdown 報告\"\"\"\n template = \"\"\"\n# 農產品對沖基金部位追蹤報告\n\n> **報告日期**: {generated_at}\n> **資料截止**: {as_of}(COT 週截止日)\n\n---\n\n## TL;DR\n\n**{call}** (信心: {confidence:.0%})\n\n{primary_reason}\n\n---\n\n## 最新指標\n\n### 週流量(合約數)\n\n| 群組 | 流量 | 淨部位 | 火力 |\n|----------|----------|--------------|--------|\n| 穀物 | {grains_flow:+,} | {grains_pos:,} | {grains_fp:.0%} |\n| 油籽 | {oilseeds_flow:+,} | {oilseeds_pos:,} | {oilseeds_fp:.0%} |\n| 肉類 | {meats_flow:+,} | {meats_pos:,} | {meats_fp:.0%} |\n| 軟性商品 | {softs_flow:+,} | {softs_pos:,} | {softs_fp:.0%} |\n| **總計** | **{total_flow:+,}** | **{total_pos:,}** | **{total_fp:.0%}** |\n\n### 宏觀順風評分: {macro_score:.0%}\n\n---\n\n## 結論依據\n\n{reasons}\n\n---\n\n## 風險提示\n\n{risks}\n\n---\n\n*本報告由 track-agri-hedge-fund-positioning v{version} 生成*\n\"\"\"\n\n # 填充模板\n metrics = result['latest_metrics']\n summary = result['summary']\n\n return template.format(\n generated_at=result['generated_at'],\n as_of=result['as_of'],\n call=summary['call'],\n confidence=summary['confidence'],\n primary_reason=summary['why'][0],\n grains_flow=metrics['flow_by_group_contracts']['grains'],\n grains_pos=metrics['net_position_by_group']['grains'],\n grains_fp=metrics['buying_firepower']['grains'],\n oilseeds_flow=metrics['flow_by_group_contracts']['oilseeds'],\n oilseeds_pos=metrics['net_position_by_group']['oilseeds'],\n oilseeds_fp=metrics['buying_firepower']['oilseeds'],\n meats_flow=metrics['flow_by_group_contracts']['meats'],\n meats_pos=metrics['net_position_by_group']['meats'],\n meats_fp=metrics['buying_firepower']['meats'],\n softs_flow=metrics['flow_by_group_contracts']['softs'],\n softs_pos=metrics['net_position_by_group']['softs'],\n softs_fp=metrics['buying_firepower']['softs'],\n total_flow=metrics['flow_total_contracts'],\n total_pos=metrics['net_position_by_group']['total'],\n total_fp=metrics['buying_firepower']['total'],\n macro_score=metrics['macro_tailwind_score'],\n reasons='\\n'.join(f'- {r}' for r in summary['why']),\n risks='\\n'.join(f'- ⚠️ {r}' for r in summary['risks']),\n version=result['version']\n )\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6719,"content_sha256":"357313ac864233d0e1c9845bee135112806b65f8f159152bab8fc21eb80a8ba2"},{"filename":"workflows/analyze.md","content":"# Workflow: 完整資金流向分析\n\n\u003crequired_reading>\n**執行前請先閱讀:**\n1. references/methodology.md\n2. references/data-sources.md\n3. references/input-schema.md\n4. references/contracts-map.md\n\u003c/required_reading>\n\n\u003cprocess>\n\n## Step 1: 參數確認與驗證\n\n確認使用者提供的參數,或使用預設值:\n\n```python\nparams = {\n \"date_start\": user_input.get(\"date_start\", \"2025-01-01\"),\n \"date_end\": user_input.get(\"date_end\", \"today\"),\n \"cot_report\": user_input.get(\"cot_report\", \"legacy\"),\n \"trader_group\": user_input.get(\"trader_group\", \"noncommercial\"),\n \"position_metric\": user_input.get(\"position_metric\", \"net\"),\n \"lookback_weeks_firepower\": user_input.get(\"lookback_weeks_firepower\", 156),\n \"output_mode\": user_input.get(\"output_mode\", \"both\")\n}\n```\n\n驗證:\n- [ ] 日期格式正確 (YYYY-MM-DD)\n- [ ] cot_report 為 legacy / disaggregated / tff 之一\n- [ ] trader_group 對應 cot_report 類型\n\n## Step 2: 抓取 COT 資料\n\n執行 `scripts/fetch_cot_data.py`:\n\n```bash\npython scripts/fetch_cot_data.py \\\n --report {cot_report} \\\n --start {date_start} \\\n --end {date_end} \\\n --output cache/cot_data.parquet\n```\n\n預期輸出:\n- 每週每商品的 long / short / spreading / open_interest\n- 欄位:date, contract, long, short, spreading, open_interest\n\n## Step 3: 抓取宏觀指標\n\n執行 `scripts/fetch_macro_data.py`:\n\n```bash\npython scripts/fetch_macro_data.py \\\n --indicators dxy,wti,metals \\\n --start {date_start} \\\n --end {date_end} \\\n --output cache/macro_data.parquet\n```\n\n預期輸出:\n- 日頻資料:date, dxy, wti, metals (或代理 ETF)\n- 計算 weekly return 用於 macro_tailwind_score\n\n## Step 4: 計算基金流量與分組彙總\n\n執行主分析腳本 `scripts/analyze_positioning.py`:\n\n```python\n# 核心邏輯摘要\ndf = load_cot_data()\ndf[\"group\"] = df[\"contract\"].map(contracts_map)\n\n# 計算淨部位與流量\nif position_metric == \"net\":\n df[\"pos\"] = df[\"long\"] - df[\"short\"]\ndf[\"flow\"] = df.groupby(\"contract\")[\"pos\"].diff()\n\n# 分組彙總\nflows = df.groupby([\"date\", \"group\"])[\"flow\"].sum().unstack()\nflows[\"total\"] = flows[[\"grains\", \"oilseeds\", \"meats\", \"softs\"]].sum(axis=1)\n```\n\n## Step 5: 計算火力分數\n\n```python\ndef calculate_firepower(net_pos_series, lookback_weeks=156):\n \"\"\"計算 buying firepower\"\"\"\n hist = net_pos_series.iloc[-lookback_weeks:]\n current = net_pos_series.iloc[-1]\n percentile = (hist \u003c= current).mean()\n return 1 - percentile # 越低的部位 = 越高的火力\n\nfirepower = {}\nfor group in [\"total\", \"grains\", \"oilseeds\", \"meats\", \"softs\"]:\n net_pos = df.groupby([\"date\", \"group\"])[\"pos\"].sum().unstack()[group]\n firepower[group] = calculate_firepower(net_pos)\n```\n\n## Step 6: 計算宏觀順風評分\n\n```python\nmacro_df = load_macro_data()\nlatest = macro_df.iloc[-1]\n\ntailwind_flags = [\n latest[\"dxy_ret\"] \u003c 0, # USD 走弱\n latest[\"wti_ret\"] > 0, # 原油走強\n latest[\"metals_ret\"] > 0 # 金屬走強\n]\n\nmacro_tailwind_score = sum(tailwind_flags) / len(tailwind_flags)\n```\n\n## Step 7: 產生訊號與呼叫\n\n```python\ndef generate_call(flow_total, firepower_total, macro_score):\n \"\"\"產生可交易呼叫\"\"\"\n signals = []\n\n # Signal 1: Funds back & buying\n if flow_total > 0 and firepower_total > 0.5:\n signals.append(\"Funds back & buying\")\n\n # Signal 2: Macro tailwind\n if macro_score >= 0.67:\n signals.append(\"Macro mood bullish\")\n\n # Signal 3: Crowded risk\n if firepower_total \u003c 0.2:\n signals.append(\"Crowded positioning - caution\")\n\n return signals\n```\n\n## Step 8: 生成標註規則\n\n依據 `templates/annotations.md` 的規則對照表:\n\n```python\nannotations = []\n\n# Strong Corn Demand\nif corn_export_surprise > 0 and grains_flow > 0:\n annotations.append({\n \"label\": \"strong_corn_demand\",\n \"rule_hit\": True,\n \"evidence\": [\"Export sales up\", \"Grains flow positive\"]\n })\n\n# Bearish USDA Stats\nif usda_surprise \u003c 0 and grains_flow \u003c 0:\n annotations.append({\n \"label\": \"bearish_usda_stats\",\n \"rule_hit\": True,\n \"evidence\": [\"WASDE bearish\", \"Grains outflow\"]\n })\n```\n\n## Step 9: 組裝輸出\n\n依據 `templates/output-json.md` 格式輸出:\n\n```python\nresult = {\n \"skill\": \"track-agri-hedge-fund-positioning\",\n \"as_of\": date_end,\n \"summary\": {\n \"call\": primary_call,\n \"confidence\": confidence_score,\n \"why\": reasons_list,\n \"risks\": risks_list\n },\n \"latest_metrics\": {\n \"cot_week_end\": cot_week_end,\n \"flow_total_contracts\": flow_total,\n \"flow_by_group_contracts\": flow_by_group,\n \"buying_firepower\": firepower,\n \"macro_tailwind_score\": macro_score\n },\n \"weekly_flows\": weekly_flows_list,\n \"annotations\": annotations\n}\n```\n\n## Step 10: 輸出報告\n\n依據 output_mode 輸出:\n- `json`:儲存至 `output/result.json`\n- `markdown`:依據 `templates/output-markdown.md` 格式輸出\n- `both`:兩者皆輸出\n\n\u003c/process>\n\n\u003csuccess_criteria>\n此工作流程完成時應確認:\n\n- [ ] COT 資料成功抓取並解析\n- [ ] 分組彙總計算正確(Grains/Oilseeds/Meats/Softs/Total)\n- [ ] 火力分數落在 0-1 範圍\n- [ ] 宏觀順風評分計算完成\n- [ ] 產生至少一個可交易呼叫\n- [ ] 輸出格式符合 template 定義\n- [ ] 風險提示已包含\n\u003c/success_criteria>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5374,"content_sha256":"26fd0ee9ac655bb43c2b1be49b27dda6f9569256e87217aa232ba4928d8037b2"},{"filename":"workflows/cross-check.md","content":"# Workflow: 宏觀與基本面交叉驗證\n\n\u003crequired_reading>\n**執行前請先閱讀:**\n1. references/methodology.md\n2. references/macro-indicators.md\n\u003c/required_reading>\n\n\u003cprocess>\n\n## Step 1: 確認驗證目標\n\n交叉驗證的核心問題:\n- COT 週資料只到週二,週三~週五的「買回」是否有代理證據?\n- 資金流向是否與宏觀風向一致?\n- 基本面事件是否支持當週的流量變化?\n\n```python\nvalidation_targets = {\n \"wed_fri_buyback\": \"週三~週五是否出現回補跡象\",\n \"macro_alignment\": \"資金流向與宏觀指標是否同向\",\n \"fundamental_trigger\": \"是否有對應的基本面事件\"\n}\n```\n\n## Step 2: 週中回補驗證(Wed-Fri)\n\n```python\ndef validate_wed_fri_buyback(cot_week_end, price_df, macro_df):\n \"\"\"驗證週三~週五的回補跡象\"\"\"\n\n # 取得 Wed-Fri 的資料\n wed = cot_week_end + timedelta(days=1) # COT 截止週二\n fri = cot_week_end + timedelta(days=3)\n\n wed_fri_data = price_df.loc[wed:fri]\n\n evidence = {\n \"price_momentum\": None,\n \"volume_change\": None,\n \"macro_resonance\": None\n }\n\n # 1. 價格動能\n if len(wed_fri_data) > 0:\n wed_fri_return = (wed_fri_data['close'].iloc[-1] /\n wed_fri_data['close'].iloc[0] - 1)\n evidence[\"price_momentum\"] = {\n \"value\": wed_fri_return,\n \"signal\": \"bullish\" if wed_fri_return > 0.005 else\n \"bearish\" if wed_fri_return \u003c -0.005 else \"neutral\"\n }\n\n # 2. 成交量變化\n if 'volume' in wed_fri_data.columns:\n avg_volume = price_df['volume'].rolling(20).mean().iloc[-1]\n wed_fri_volume = wed_fri_data['volume'].mean()\n vol_ratio = wed_fri_volume / avg_volume\n evidence[\"volume_change\"] = {\n \"value\": vol_ratio,\n \"signal\": \"elevated\" if vol_ratio > 1.2 else \"normal\"\n }\n\n # 3. 宏觀共振\n macro_wed_fri = macro_df.loc[wed:fri]\n if len(macro_wed_fri) > 0:\n usd_down = macro_wed_fri['dxy_ret'].sum() \u003c 0\n oil_up = macro_wed_fri['wti_ret'].sum() > 0\n metals_up = macro_wed_fri['metals_ret'].sum() > 0\n\n resonance_score = sum([usd_down, oil_up, metals_up]) / 3\n evidence[\"macro_resonance\"] = {\n \"value\": resonance_score,\n \"details\": {\n \"usd_down\": usd_down,\n \"oil_up\": oil_up,\n \"metals_up\": metals_up\n },\n \"signal\": \"supportive\" if resonance_score >= 0.67 else\n \"mixed\" if resonance_score >= 0.33 else \"unsupportive\"\n }\n\n return evidence\n```\n\n## Step 3: 宏觀一致性驗證\n\n```python\ndef validate_macro_alignment(flow_direction, macro_score):\n \"\"\"驗證資金流向與宏觀指標的一致性\"\"\"\n\n alignment = {\n \"flow_direction\": \"inflow\" if flow_direction > 0 else \"outflow\",\n \"macro_bias\": \"bullish\" if macro_score >= 0.67 else\n \"bearish\" if macro_score \u003c= 0.33 else \"neutral\",\n \"aligned\": None,\n \"interpretation\": None\n }\n\n # 判斷一致性\n if flow_direction > 0 and macro_score >= 0.5:\n alignment[\"aligned\"] = True\n alignment[\"interpretation\"] = \"資金流入且宏觀順風,敘事一致\"\n elif flow_direction \u003c 0 and macro_score \u003c= 0.5:\n alignment[\"aligned\"] = True\n alignment[\"interpretation\"] = \"資金流出且宏觀逆風,敘事一致\"\n elif flow_direction > 0 and macro_score \u003c 0.5:\n alignment[\"aligned\"] = False\n alignment[\"interpretation\"] = \"資金流入但宏觀逆風,需警惕反轉\"\n else:\n alignment[\"aligned\"] = False\n alignment[\"interpretation\"] = \"資金流出但宏觀順風,可能是超賣反彈機會\"\n\n return alignment\n```\n\n## Step 4: 基本面事件匹配\n\n```python\nFUNDAMENTAL_EVENTS = {\n \"export_sales\": {\n \"source\": \"USDA FAS Weekly Export Sales\",\n \"frequency\": \"weekly\",\n \"impact_groups\": [\"grains\", \"oilseeds\"]\n },\n \"wasde_release\": {\n \"source\": \"USDA WASDE\",\n \"frequency\": \"monthly\",\n \"impact_groups\": [\"grains\", \"oilseeds\", \"meats\", \"softs\"]\n },\n \"crop_progress\": {\n \"source\": \"USDA Crop Progress\",\n \"frequency\": \"weekly\",\n \"impact_groups\": [\"grains\", \"oilseeds\"]\n },\n \"cattle_on_feed\": {\n \"source\": \"USDA Cattle on Feed\",\n \"frequency\": \"monthly\",\n \"impact_groups\": [\"meats\"]\n }\n}\n\ndef match_fundamental_events(cot_week_end, flow_by_group):\n \"\"\"匹配當週的基本面事件\"\"\"\n week_start = cot_week_end - timedelta(days=6)\n\n matched_events = []\n\n for event_name, event_info in FUNDAMENTAL_EVENTS.items():\n # 檢查該週是否有事件發布\n event_dates = get_event_dates(event_name, week_start, cot_week_end)\n\n if event_dates:\n # 取得事件內容\n event_data = fetch_event_data(event_name, event_dates[-1])\n\n # 判斷事件偏向\n bias = interpret_event_bias(event_data)\n\n # 檢查與流量方向的一致性\n for group in event_info[\"impact_groups\"]:\n if group in flow_by_group:\n flow = flow_by_group[group]\n consistent = (bias == \"bullish\" and flow > 0) or \\\n (bias == \"bearish\" and flow \u003c 0)\n\n matched_events.append({\n \"event\": event_name,\n \"date\": str(event_dates[-1]),\n \"bias\": bias,\n \"group\": group,\n \"flow\": flow,\n \"consistent\": consistent\n })\n\n return matched_events\n```\n\n## Step 5: 生成驗證報告\n\n```python\ndef generate_validation_report(cot_result, validation_results):\n \"\"\"生成交叉驗證報告\"\"\"\n\n report = {\n \"validation_timestamp\": datetime.now().isoformat(),\n \"cot_week_end\": cot_result[\"cot_week_end\"],\n\n \"wed_fri_validation\": validation_results[\"wed_fri\"],\n \"macro_alignment\": validation_results[\"macro\"],\n \"fundamental_events\": validation_results[\"fundamentals\"],\n\n \"overall_consistency\": None,\n \"confidence_adjustment\": None,\n \"narrative_assessment\": None\n }\n\n # 計算整體一致性分數\n consistency_scores = []\n\n # Wed-Fri 驗證\n wed_fri = validation_results[\"wed_fri\"]\n if wed_fri[\"price_momentum\"][\"signal\"] == \"bullish\":\n consistency_scores.append(1)\n elif wed_fri[\"price_momentum\"][\"signal\"] == \"bearish\":\n consistency_scores.append(0)\n else:\n consistency_scores.append(0.5)\n\n # 宏觀一致性\n if validation_results[\"macro\"][\"aligned\"]:\n consistency_scores.append(1)\n else:\n consistency_scores.append(0)\n\n # 基本面一致性\n fundamentals = validation_results[\"fundamentals\"]\n if fundamentals:\n fund_score = sum(1 for f in fundamentals if f[\"consistent\"]) / len(fundamentals)\n consistency_scores.append(fund_score)\n\n report[\"overall_consistency\"] = sum(consistency_scores) / len(consistency_scores)\n\n # 信心調整\n if report[\"overall_consistency\"] >= 0.7:\n report[\"confidence_adjustment\"] = 0.1 # 增加 10% 信心\n report[\"narrative_assessment\"] = \"敘事高度一致,可信度高\"\n elif report[\"overall_consistency\"] >= 0.5:\n report[\"confidence_adjustment\"] = 0\n report[\"narrative_assessment\"] = \"敘事部分一致,需持續觀察\"\n else:\n report[\"confidence_adjustment\"] = -0.15 # 降低 15% 信心\n report[\"narrative_assessment\"] = \"敘事存在矛盾,謹慎對待\"\n\n return report\n```\n\n## Step 6: 輸出驗證結果\n\n```bash\npython scripts/cross_check.py \\\n --cot-result output/result.json \\\n --output output/validation_report.json\n```\n\n\u003c/process>\n\n\u003csuccess_criteria>\n此工作流程完成時應確認:\n\n- [ ] Wed-Fri 價格動能已計算\n- [ ] 宏觀一致性已評估\n- [ ] 基本面事件已匹配\n- [ ] 整體一致性分數落在 0-1 範圍\n- [ ] 信心調整建議已給出\n- [ ] 敘事評估結論明確\n\u003c/success_criteria>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8170,"content_sha256":"611b927047d5a4894110174087e46a3f5c77bd489c58a509420043af6ce6f377"},{"filename":"workflows/monitor.md","content":"# Workflow: 週度監控與警報\n\n\u003crequired_reading>\n**執行前請先閱讀:**\n1. references/methodology.md\n2. references/data-sources.md\n\u003c/required_reading>\n\n\u003cprocess>\n\n## Step 1: 確認 COT 發布時間\n\nCFTC COT 報告發布時間表:\n- **截止日**:每週二收盤\n- **發布日**:每週五 15:30 ET(美東時間)\n- **例外**:遇假日可能延後\n\n```python\nfrom datetime import datetime, timedelta\nimport pytz\n\ndef get_next_cot_release():\n \"\"\"計算下一次 COT 發布時間\"\"\"\n et = pytz.timezone('US/Eastern')\n now = datetime.now(et)\n\n # 找到下一個週五\n days_until_friday = (4 - now.weekday()) % 7\n if days_until_friday == 0 and now.hour >= 16:\n days_until_friday = 7\n\n next_friday = now + timedelta(days=days_until_friday)\n release_time = next_friday.replace(hour=15, minute=30, second=0)\n\n return release_time\n```\n\n## Step 2: 設定監控排程\n\n建議監控頻率:\n\n| 時間點 | 動作 |\n|------------------|------------------------------|\n| 週五 16:00 ET | 抓取最新 COT 資料 |\n| 週五 16:30 ET | 執行完整分析 |\n| 週一開盤前 | 檢查 Wed-Fri 價格動能 |\n| 週中 USDA 發布後 | 交叉驗證基本面 |\n\n```bash\n# 設定 cron job 範例(週五 16:00 ET)\n0 16 * * 5 cd /path/to/skill && python scripts/analyze_positioning.py --quick --alert\n```\n\n## Step 3: 定義警報條件\n\n```python\nALERT_CONDITIONS = {\n # 高優先級警報\n \"regime_change\": {\n \"condition\": lambda r: abs(r['flow_total']) > threshold_high and\n r['prev_flow_total'] * r['flow_total'] \u003c 0,\n \"message\": \"Regime change detected: Flow reversed sign\",\n \"priority\": \"high\"\n },\n\n # 中優先級警報\n \"firepower_extreme\": {\n \"condition\": lambda r: r['firepower_total'] \u003c 0.15 or\n r['firepower_total'] > 0.85,\n \"message\": \"Extreme firepower level detected\",\n \"priority\": \"medium\"\n },\n\n # 低優先級警報\n \"macro_divergence\": {\n \"condition\": lambda r: (r['flow_total'] > 0 and r['macro_score'] \u003c 0.33) or\n (r['flow_total'] \u003c 0 and r['macro_score'] > 0.67),\n \"message\": \"Macro divergence: Flow and macro signals misaligned\",\n \"priority\": \"low\"\n }\n}\n```\n\n## Step 4: 執行監控分析\n\n```bash\npython scripts/analyze_positioning.py \\\n --mode monitor \\\n --lookback-weeks 4 \\\n --alert-config config/alert_rules.yaml \\\n --output monitor_result.json\n```\n\n輸出範例:\n```json\n{\n \"monitor_timestamp\": \"2026-01-24T16:30:00-05:00\",\n \"cot_week_end\": \"2026-01-21\",\n \"alerts_triggered\": [\n {\n \"alert_id\": \"firepower_extreme\",\n \"priority\": \"medium\",\n \"message\": \"Extreme firepower level detected\",\n \"details\": {\n \"firepower_total\": 0.12,\n \"interpretation\": \"Crowded long positioning\"\n }\n }\n ],\n \"week_over_week_changes\": {\n \"flow_total\": {\"current\": -25, \"previous\": 58, \"change\": -83},\n \"firepower_total\": {\"current\": 0.12, \"previous\": 0.18, \"change\": -0.06}\n }\n}\n```\n\n## Step 5: 發送通知\n\n支援多種通知管道:\n\n```python\ndef send_alert(alert_data, channels=['log']):\n \"\"\"發送警報通知\"\"\"\n for channel in channels:\n if channel == 'log':\n log_alert(alert_data)\n elif channel == 'email':\n send_email_alert(alert_data)\n elif channel == 'slack':\n send_slack_alert(alert_data)\n elif channel == 'telegram':\n send_telegram_alert(alert_data)\n\n# 設定檔範例 (config/alert_channels.yaml)\n\"\"\"\nchannels:\n - type: log\n path: logs/alerts.log\n\n - type: slack\n webhook_url: ${SLACK_WEBHOOK_URL}\n channel: \"#trading-alerts\"\n\n - type: email\n smtp_server: smtp.gmail.com\n recipients:\n - [email protected]\n\"\"\"\n```\n\n## Step 6: 歷史比對\n\n監控時自動比對歷史類似情境:\n\n```python\ndef find_similar_episodes(current_state, history_df, top_n=3):\n \"\"\"找出歷史上的類似情境\"\"\"\n similarity_scores = []\n\n for date, row in history_df.iterrows():\n # 計算特徵相似度\n features = ['firepower_total', 'macro_score', 'flow_direction']\n score = compute_similarity(current_state, row, features)\n similarity_scores.append((date, score, row))\n\n # 排序並返回最相似的 N 個\n similar = sorted(similarity_scores, key=lambda x: x[1], reverse=True)[:top_n]\n\n return [\n {\n \"date\": str(s[0]),\n \"similarity\": s[1],\n \"subsequent_move\": get_subsequent_move(s[0], history_df)\n }\n for s in similar\n ]\n```\n\n## Step 7: 生成週報\n\n每週五分析後自動生成週報:\n\n```bash\npython scripts/generate_weekly_report.py \\\n --result monitor_result.json \\\n --template templates/output-markdown.md \\\n --output reports/weekly_2026-01-24.md\n```\n\n\u003c/process>\n\n\u003csuccess_criteria>\n此工作流程完成時應確認:\n\n- [ ] 在 COT 發布後及時執行分析\n- [ ] 警報條件正確觸發\n- [ ] 通知成功發送至指定管道\n- [ ] 週報自動生成\n- [ ] 歷史比對提供參考情境\n- [ ] 監控日誌完整記錄\n\u003c/success_criteria>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5247,"content_sha256":"3f10f504145b501b2e5ed78bfa6512ac8a237ffd0193d911d630f08894c49fe0"},{"filename":"workflows/visualize.md","content":"# Workflow: 視覺化圖表\n\n\u003crequired_reading>\n**執行前請先閱讀:**\n1. references/methodology.md\n2. templates/annotations.md\n\u003c/required_reading>\n\n\u003cprocess>\n\n## Step 1: 確認輸入資料\n\n需要以下資料作為輸入:\n- 分析結果 JSON(來自 `workflows/analyze.md` 輸出)\n- 或直接重新執行分析\n\n```bash\n# 使用既有分析結果\npython scripts/visualize_flows.py -i output/result.json -o output/chart.png\n\n# 或重新分析並視覺化\npython scripts/analyze_positioning.py --full --visualize\n```\n\n## Step 2: 生成分組柱狀圖\n\n重建新聞風格的週流量柱狀圖:\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\ndef plot_weekly_flows(flows_df, output_path):\n \"\"\"生成分組柱狀圖\"\"\"\n fig, ax = plt.subplots(figsize=(14, 7))\n\n dates = flows_df.index\n width = 0.15\n x = np.arange(len(dates))\n\n # 分組柱狀\n colors = {\n 'grains': '#F4A460', # 橙色\n 'oilseeds': '#32CD32', # 綠色\n 'meats': '#DC143C', # 紅色\n 'softs': '#8B4513' # 棕色\n }\n\n for i, (group, color) in enumerate(colors.items()):\n ax.bar(x + i*width, flows_df[group], width,\n label=group.capitalize(), color=color)\n\n # 總和線\n ax.plot(x + 2*width, flows_df['total'], 'k-o',\n label='Total', linewidth=2)\n\n ax.axhline(y=0, color='gray', linestyle='--', alpha=0.5)\n ax.set_xlabel('Week')\n ax.set_ylabel('Net Flow (# contracts)')\n ax.set_title('Hedge Fund Positioning: Weekly Flows by Group')\n ax.legend()\n\n plt.tight_layout()\n plt.savefig(output_path, dpi=150)\n plt.close()\n```\n\n## Step 3: 生成火力時序圖\n\n```python\ndef plot_firepower_timeseries(firepower_df, output_path):\n \"\"\"生成火力時序圖\"\"\"\n fig, axes = plt.subplots(2, 1, figsize=(14, 10))\n\n # 上圖:各群組火力\n for group in ['grains', 'oilseeds', 'meats', 'softs']:\n axes[0].plot(firepower_df.index, firepower_df[group],\n label=group.capitalize())\n\n axes[0].axhline(y=0.6, color='green', linestyle='--',\n alpha=0.5, label='High Firepower Zone')\n axes[0].axhline(y=0.3, color='red', linestyle='--',\n alpha=0.5, label='Low Firepower Zone')\n axes[0].fill_between(firepower_df.index, 0.6, 1.0,\n alpha=0.1, color='green')\n axes[0].fill_between(firepower_df.index, 0.0, 0.3,\n alpha=0.1, color='red')\n\n axes[0].set_ylabel('Buying Firepower')\n axes[0].set_title('Buying Firepower by Group')\n axes[0].legend()\n axes[0].set_ylim(0, 1)\n\n # 下圖:總火力與宏觀評分\n axes[1].plot(firepower_df.index, firepower_df['total'],\n 'b-', label='Total Firepower', linewidth=2)\n axes[1].set_ylabel('Total Firepower', color='blue')\n\n ax2 = axes[1].twinx()\n ax2.plot(firepower_df.index, firepower_df['macro_score'],\n 'orange', label='Macro Tailwind', linewidth=2)\n ax2.set_ylabel('Macro Tailwind Score', color='orange')\n\n axes[1].set_title('Total Firepower vs Macro Tailwind')\n axes[1].legend(loc='upper left')\n ax2.legend(loc='upper right')\n\n plt.tight_layout()\n plt.savefig(output_path, dpi=150)\n plt.close()\n```\n\n## Step 4: 添加標註\n\n依據 `templates/annotations.md` 的規則,在圖表上添加事件標註:\n\n```python\ndef add_annotations(ax, annotations_list, flows_df):\n \"\"\"在圖表上添加事件標註\"\"\"\n label_styles = {\n 'strong_corn_demand': {'color': 'green', 'marker': '^'},\n 'bearish_usda_stats': {'color': 'red', 'marker': 'v'},\n 'macro_mood_bullish': {'color': 'blue', 'marker': 'o'},\n 'small_holiday_flows': {'color': 'gray', 'marker': 's'}\n }\n\n for ann in annotations_list:\n if ann['rule_hit']:\n date = ann.get('date')\n idx = flows_df.index.get_loc(date)\n style = label_styles.get(ann['label'], {})\n\n ax.annotate(\n ann['label'].replace('_', ' ').title(),\n xy=(idx, flows_df.loc[date, 'total']),\n xytext=(10, 10),\n textcoords='offset points',\n fontsize=8,\n arrowprops=dict(arrowstyle='->', color=style.get('color', 'black'))\n )\n```\n\n## Step 5: 生成綜合儀表板\n\n```python\ndef create_dashboard(result_json, output_path):\n \"\"\"生成綜合儀表板\"\"\"\n fig = plt.figure(figsize=(16, 12))\n\n # 布局:2x2 格子\n gs = fig.add_gridspec(2, 2, hspace=0.3, wspace=0.3)\n\n # 左上:週流量柱狀圖\n ax1 = fig.add_subplot(gs[0, 0])\n plot_weekly_flows_subplot(ax1, result_json['weekly_flows'])\n\n # 右上:火力儀表\n ax2 = fig.add_subplot(gs[0, 1])\n plot_firepower_gauge(ax2, result_json['latest_metrics']['buying_firepower'])\n\n # 左下:宏觀順風指標\n ax3 = fig.add_subplot(gs[1, 0])\n plot_macro_indicators(ax3, result_json)\n\n # 右下:摘要卡片\n ax4 = fig.add_subplot(gs[1, 1])\n plot_summary_card(ax4, result_json['summary'])\n\n plt.savefig(output_path, dpi=150, bbox_inches='tight')\n plt.close()\n```\n\n## Step 6: 輸出檔案\n\n```bash\n# 輸出目錄結構\noutput/\n├── flows_chart.png # 週流量柱狀圖\n├── firepower_chart.png # 火力時序圖\n├── dashboard.png # 綜合儀表板\n└── charts/ # 單獨群組圖表\n ├── grains.png\n ├── oilseeds.png\n ├── meats.png\n └── softs.png\n```\n\n\u003c/process>\n\n\u003csuccess_criteria>\n此工作流程完成時應確認:\n\n- [ ] 週流量柱狀圖成功生成(重建新聞風格)\n- [ ] 各群組顏色區分清楚\n- [ ] 火力分數圖包含區間標示(綠/紅區)\n- [ ] 事件標註正確顯示\n- [ ] 圖表解析度足夠(>= 150 dpi)\n- [ ] 輸出至指定路徑\n\u003c/success_criteria>\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5853,"content_sha256":"396d50e16b59977362248f9505c82c2562bb39c55f5531b8296664b83ef0db0d"}],"content_json":{"type":"doc","content":[{"type":"paragraph","content":[{"text":"\u003cessential_principles>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cprinciple name=\"cot_as_flow_proxy\"> ","type":"text"},{"text":"COT 週資料作為資金流代理","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"CFTC Commitments of Traders 報告是追蹤對沖基金農產品部位的核心資料:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"截止日","type":"text","marks":[{"type":"strong"}]},{"text":":每週二收盤","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"發布日","type":"text","marks":[{"type":"strong"}]},{"text":":每週五下午 3:30 ET","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"交易者分類","type":"text","marks":[{"type":"strong"}]},{"text":":非商業(投機/基金)、商業(避險)、非報告","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"資金流 = 本週淨部位 - 上週淨部位(以合約口數計) \u003c/principle>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cprinciple name=\"group_aggregation\"> ","type":"text"},{"text":"分組彙總邏輯","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"使用 CFTC 原生分組(commodity_subgroup_name):","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"群組","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CFTC 分組名稱","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"包含商品","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Grains","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"GRAINS","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Corn, Wheat (SRW/HRW/HRS), Oats","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Oilseeds","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OILSEED and PRODUCTS","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Soybeans, Soybean Oil/Meal, Canola","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meats","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"LIVESTOCK/MEAT PRODUCTS","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Live Cattle, Lean Hogs, Feeder","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Softs","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FOODSTUFFS/SOFTS","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Coffee, Sugar, Cocoa, OJ","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fiber","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FIBER","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cotton","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dairy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"DAIRY PRODUCTS","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Milk, Butter, Cheese","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Total Flow = Grains + Oilseeds + Meats + Softs + Fiber + Dairy","type":"text","marks":[{"type":"strong"}]},{"text":" \u003c/principle>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cprinciple name=\"firepower_definition\"> ","type":"text"},{"text":"火力(Buying Firepower)量化","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"火力衡量基金是否還有加碼空間:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"net_pos_percentile = rank(current_net_pos, past_N_weeks)\nfirepower = 1 - net_pos_percentile","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"高火力(>0.6)","type":"text","marks":[{"type":"strong"}]},{"text":":部位處於歷史低檔,仍有大量買進空間","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"低火力(\u003c0.3)","type":"text","marks":[{"type":"strong"}]},{"text":":部位已接近歷史高檔,擁擠風險高 \u003c/principle>","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"\u003cprinciple name=\"macro_tailwind\"> ","type":"text"},{"text":"宏觀順風評分","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"整合三個風險偏好指標:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"指標","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"訊號解讀","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"美元 (DXY)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"走弱(負報酬)= 利於商品","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"原油 (WTI)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"走強(正報酬)= 風險偏好上升","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"金屬","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"走強(正報酬)= 循環需求樂觀","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"macro_tailwind_score = (DXY弱 + WTI強 + Metals強) / 3","type":"text","marks":[{"type":"strong"}]},{"text":" \u003c/principle>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cprinciple name=\"wed_fri_validation\"> ","type":"text"},{"text":"週中回補驗證框架","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"COT 只到週二,週三~週五需用代理證據:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"價格動能","type":"text","marks":[{"type":"strong"}]},{"text":":農產品/代理指數 Wed-Fri 累積報酬","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"未平倉變化","type":"text","marks":[{"type":"strong"}]},{"text":":OI 擴張 = 新倉(非純換手)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"宏觀共振","type":"text","marks":[{"type":"strong"}]},{"text":":與 USD↓、油價↑、金屬↑ 同時性 \u003c/principle>","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"\u003c/essential_principles>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cobjective> 追蹤對沖基金在農產品期貨的部位變化與資金流向:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"取得資料","type":"text","marks":[{"type":"strong"}]},{"text":":COT 週報、宏觀指標(DXY/WTI/金屬)、基本面觸發(出口/USDA)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"計算流量","type":"text","marks":[{"type":"strong"}]},{"text":":淨部位週變化,分組彙總(Grains/Oilseeds/Meats/Softs/Total)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"量化火力","type":"text","marks":[{"type":"strong"}]},{"text":":用歷史分位數估算基金加碼空間","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"整合訊號","type":"text","marks":[{"type":"strong"}]},{"text":":判斷「基金回來買」+ 「宏觀順風」+ 「基本面支持」","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"產出敘事","type":"text","marks":[{"type":"strong"}]},{"text":":將圖表標註(如 Strong Corn Demand)轉為可重複的規則","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"輸出:週流量時序、最新狀態、火力分數、宏觀評分、可交易註解。 \u003c/objective>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cquick_start>","type":"text"}]},{"type":"paragraph","content":[{"text":"快速開始:分析最新 COT 資料","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cd .claude/skills/track-agri-hedge-fund-positioning/scripts\npip install pandas numpy requests yfinance pyarrow # 首次使用\npython analyze_positioning.py --start 2023-01-01","type":"text"}]},{"type":"paragraph","content":[{"text":"輸出範例(真實資料):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"skill\": \"track-agri-hedge-fund-positioning\",\n \"as_of\": \"2026-01-20\",\n \"data_source\": \"CFTC Socrata API (real data)\",\n \"summary\": {\n \"call\": \"Funds continue selling\",\n \"all_signals\": [\"Funds continue selling\", \"Extreme short - watch for reversal\", \"Macro mood bullish\"],\n \"confidence\": 0.90\n },\n \"latest_metrics\": {\n \"flow_total_contracts\": -24559,\n \"flow_by_group_contracts\": {\"grains\": -31279, \"oilseeds\": 11517, \"meats\": 18972, \"softs\": -23887, \"fiber\": 1607, \"dairy\": -1489},\n \"buying_firepower\": {\"total\": 0.86, \"grains\": 0.58, \"oilseeds\": 0.62, \"meats\": 0.31, \"softs\": 0.99, \"fiber\": 0.58, \"dairy\": 0.99},\n \"macro_tailwind_score\": 0.67\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"視覺化圖表","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python visualize_flows.py --weeks 52\n# 輸出:output/agri_fund_positioning_YYYY-MM-DD.png","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003c/quick_start>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cintake> 需要進行什麼操作?","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"快速檢查","type":"text","marks":[{"type":"strong"}]},{"text":" - 查看最新一週的基金部位變化與狀態","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"完整分析","type":"text","marks":[{"type":"strong"}]},{"text":" - 指定日期範圍的資金流向分析與回測","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"視覺化圖表","type":"text","marks":[{"type":"strong"}]},{"text":" - 生成分組柱狀圖與火力時序圖","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"監控模式","type":"text","marks":[{"type":"strong"}]},{"text":" - 設定週度更新與訊號警報","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"方法論學習","type":"text","marks":[{"type":"strong"}]},{"text":" - 了解 COT 分析與火力計算邏輯","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"請選擇或直接提供分析參數。","type":"text","marks":[{"type":"strong"}]},{"text":" \u003c/intake>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003crouting>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Response","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Action","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1, \"快速\", \"quick\", \"latest\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"執行 ","type":"text"},{"text":"python scripts/analyze_positioning.py","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2, \"分析\", \"analyze\", \"full\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"執行 ","type":"text"},{"text":"python scripts/analyze_positioning.py --start DATE","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3, \"視覺化\", \"chart\", \"plot\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"執行 ","type":"text"},{"text":"python scripts/visualize_flows.py --weeks 52","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4, \"監控\", \"monitor\", \"weekly\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"閱讀 ","type":"text"},{"text":"workflows/monitor.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" 並執行","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5, \"學習\", \"方法論\", \"why\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"閱讀 ","type":"text"},{"text":"references/methodology.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"提供參數 (如日期範圍、商品)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"使用參數執行 ","type":"text"},{"text":"analyze_positioning.py","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"所有腳本使用 CFTC Socrata API 取得真實資料,無模擬數據。","type":"text","marks":[{"type":"strong"}]},{"text":" \u003c/routing>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003creference_index> ","type":"text"},{"text":"參考文件","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"references/","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文件","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"內容","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"methodology.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"COT 分析方法論、火力計算、訊號邏輯","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"data-sources.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CFTC COT、FRED、Yahoo Finance 資料來源","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"input-schema.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"完整輸入參數定義","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"contracts-map.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"期貨合約與商品群組對照表","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"macro-indicators.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"宏觀指標定義與代理序列","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/reference_index>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003cworkflows_index>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Workflow","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"使用時機","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"analyze.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"完整資金流向分析","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"需要深度分析時","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"visualize.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"生成視覺化圖表","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"需要重建新聞圖表時","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"monitor.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"週度監控與警報","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"每週五 COT 更新後","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cross-check.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"宏觀與基本面交叉驗證","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"驗證敘事一致性時","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/workflows_index>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003ctemplates_index>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Template","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"output-json.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSON 輸出結構定義","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"output-markdown.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Markdown 報告模板","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"annotations.md","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"圖表標註規則對照表","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/templates_index>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003cscripts_index>","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Script","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Command","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fetch_cot_data.py","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--start 2023-01-01 --summary","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"從 CFTC Socrata API 抓取 COT","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fetch_macro_data.py","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--start 2025-01-01 --summary","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"抓取宏觀指標(Yahoo/FRED)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"analyze_positioning.py","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--start 2023-01-01","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"主分析腳本(自動抓取+計算)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"visualize_flows.py","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--weeks 52","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"生成 Bloomberg 風格視覺化圖表","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\u003c/scripts_index>","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph"}]}]}]},{"type":"paragraph","content":[{"text":"\u003cinput_schema_summary>","type":"text"}]},{"type":"paragraph","content":[{"text":"必要參數","type":"text","marks":[{"type":"strong"}]}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"參數","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"類型","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"說明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"date_start","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"起始日期 (YYYY-MM-DD)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"date_end","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"結束日期 (YYYY-MM-DD)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cot_report","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"COT 類型 (legacy/disaggregated)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"trader_group","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"交易者分類 (noncommercial)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"contracts_map","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"object","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"合約→群組對照表","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"選用參數","type":"text","marks":[{"type":"strong"}]}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"參數","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"類型","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"預設值","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"說明","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"position_metric","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"net","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"部位衡量 (net/long/short)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"lookback_weeks_firepower","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"int","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"156","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"火力計算視窗(週)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"macro_indicators","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"object","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{...}","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"宏觀指標設定","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fundamental_inputs","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"object","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{...}","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"基本面資料設定","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"event_window_days","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"int","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Wed-Fri 事件視窗","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"output_mode","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"string","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"both","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"輸出格式 (markdown/json)","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"完整參數定義見 ","type":"text"},{"text":"references/input-schema.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003c/input_schema_summary>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003coutput_schema_summary>","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"skill\": \"track-agri-hedge-fund-positioning\",\n \"as_of\": \"2026-01-21\",\n \"summary\": {\n \"call\": \"Funds back & buying\",\n \"confidence\": 0.72,\n \"why\": [\"COT 週部位由負轉正\", \"分組同步改善\", \"宏觀順風\"],\n \"risks\": [\"COT 只到週二\", \"USDA 報告可能反轉\"]\n },\n \"latest_metrics\": {\n \"cot_week_end\": \"2026-01-21\",\n \"flow_total_contracts\": 58,\n \"flow_by_group_contracts\": {\n \"grains\": 35, \"oilseeds\": 25, \"meats\": 5, \"softs\": 0\n },\n \"buying_firepower\": {\n \"total\": 0.63, \"grains\": 0.58, \"oilseeds\": 0.67\n },\n \"macro_tailwind_score\": 0.67\n },\n \"annotations\": [\n {\"label\": \"macro_mood_bullish\", \"rule_hit\": true, \"evidence\": [\"USD down\", \"crude up\"]}\n ]\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"完整輸出結構見 ","type":"text"},{"text":"templates/output-json.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"。 \u003c/output_schema_summary>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003csuccess_criteria> 執行成功時應產出:","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"週流量時序(Grains/Oilseeds/Meats/Softs/Fiber/Dairy/Total)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"最新一週的流量與淨部位","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"各群組的火力分數(buying_firepower)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"宏觀順風評分(macro_tailwind_score)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"可交易呼叫(call)與信心水準","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"圖表標註(annotations)與規則觸發","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"風險提示與下一步建議","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Bloomberg 風格視覺化圖表(output/agri_fund_positioning_YYYY-MM-DD.png) \u003c/success_criteria>","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"track-agri-hedge-fund-positioning","author":"@skillopedia","source":{"stars":3,"repo_name":"macro-skills","origin_url":"https://github.com/fatfingererr/macro-skills/blob/HEAD/skills/track-agri-hedge-fund-positioning/SKILL.md","repo_owner":"fatfingererr","body_sha256":"26a16f0800d4e0a62fb14f179e0c6f1fc8512d4380999c18844672d0fe90f3d8","cluster_key":"a77c8397987d26c8f8879565edd4d08373254c222015517e6cc7b41194edecc9","clean_bundle":{"format":"clean-skill-bundle-v1","source":"fatfingererr/macro-skills/skills/track-agri-hedge-fund-positioning/SKILL.md","attachments":[{"id":"2dd4199d-9adf-5cd0-ab6d-4a368936628f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2dd4199d-9adf-5cd0-ab6d-4a368936628f/attachment.json","path":"examples/full_analysis_result.json","size":5301,"sha256":"cd2d528068b51e0b52296e0687bf68f4bae562ab257e4f104bf973e6e0c053e0","contentType":"application/json; charset=utf-8"},{"id":"172a8d62-9b12-52a6-bf2b-9052c0421678","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/172a8d62-9b12-52a6-bf2b-9052c0421678/attachment.json","path":"examples/weekly_flow_sample.json","size":853,"sha256":"080a72ac6b6ba1bf8d5e69f53eec8f58daa05050dfc7171949fc27cbca11d7fb","contentType":"application/json; charset=utf-8"},{"id":"b1934a1d-e8f4-52c5-8739-cb3e6660ab36","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b1934a1d-e8f4-52c5-8739-cb3e6660ab36/attachment.json","path":"manifest.json","size":2623,"sha256":"e32d252a3d4f6fb03094b4752d241231cd7d68b011a93abc73803f2a19e07b0a","contentType":"application/json; charset=utf-8"},{"id":"4050c225-29b2-5d5b-876c-3a0b0d4ef8eb","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4050c225-29b2-5d5b-876c-3a0b0d4ef8eb/attachment.md","path":"references/contracts-map.md","size":5661,"sha256":"3780e08ea0c7e6be7159e5c8f491db2e27ea6a80fec24418fdf8ebc1589e5068","contentType":"text/markdown; charset=utf-8"},{"id":"0916f037-fe73-5332-8e71-ddcf8c456a3d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0916f037-fe73-5332-8e71-ddcf8c456a3d/attachment.md","path":"references/data-sources.md","size":7287,"sha256":"271ffd8ac160147872bfba61bc7e4838a2eebf7580fb8f39508efa6a5d212e66","contentType":"text/markdown; charset=utf-8"},{"id":"1ebec674-7a98-5f85-9188-3c613a455b5d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1ebec674-7a98-5f85-9188-3c613a455b5d/attachment.md","path":"references/input-schema.md","size":7193,"sha256":"8972db073d55bd4a54f9f2130d104a11d30e3df6cc20d18a69839de8d90c052f","contentType":"text/markdown; charset=utf-8"},{"id":"170bd1e4-14b6-52a0-ae5b-0e15d5f03d78","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/170bd1e4-14b6-52a0-ae5b-0e15d5f03d78/attachment.md","path":"references/macro-indicators.md","size":8179,"sha256":"7db2d0d28fac8ce326c18b57cc5a07de07a02c43763c92de572a3256d4f89101","contentType":"text/markdown; charset=utf-8"},{"id":"b1177ad2-2ef7-50a8-abdf-b14b88b13d90","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b1177ad2-2ef7-50a8-abdf-b14b88b13d90/attachment.md","path":"references/methodology.md","size":6751,"sha256":"968243f03a312537eb1c2e27740a0dba64e8ba4d55f9586c179a65e2c65e9c15","contentType":"text/markdown; charset=utf-8"},{"id":"6fd5e16d-3b9e-5da2-a64f-819e7737eb5d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6fd5e16d-3b9e-5da2-a64f-819e7737eb5d/attachment.py","path":"scripts/analyze_positioning.py","size":14058,"sha256":"97baf21d554aff5f18f1829fc01588cfb04cdbfac4f37602b0214d8616987359","contentType":"text/x-python; charset=utf-8"},{"id":"4f273d42-0a6f-556f-9378-b2d691c60608","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4f273d42-0a6f-556f-9378-b2d691c60608/attachment.py","path":"scripts/fetch_cot_data.py","size":8138,"sha256":"7afdbe1fb0a8f5dc122a4d260ca4ddb0d31e8b087ae6cebcabea50c89ce036a1","contentType":"text/x-python; charset=utf-8"},{"id":"99a549a1-27d5-580c-bc13-e7b7be7ffecb","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/99a549a1-27d5-580c-bc13-e7b7be7ffecb/attachment.py","path":"scripts/fetch_macro_data.py","size":10161,"sha256":"a756cd5df1ab6068ed8ba06185546129709234c0476c8069d646b175e6fa6781","contentType":"text/x-python; charset=utf-8"},{"id":"7a69ea36-dfc8-5bf8-9593-b75098172133","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7a69ea36-dfc8-5bf8-9593-b75098172133/attachment.py","path":"scripts/visualize_flows.py","size":23775,"sha256":"afac79b820b1bd679d0e4f8f111a0193a8f54e07b64002260edf9151886d0732","contentType":"text/x-python; charset=utf-8"},{"id":"216d6eec-32d3-5e78-bf9d-8f58c92d517e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/216d6eec-32d3-5e78-bf9d-8f58c92d517e/attachment.yaml","path":"skill.yaml","size":16972,"sha256":"c6bbc738767c88fc3e4f6f473a539dc04d9270e87d4fc2b6142048bf7e8c8ff2","contentType":"application/yaml; charset=utf-8"},{"id":"671d4e91-1457-5b72-939a-5cd0f75c1bcd","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/671d4e91-1457-5b72-939a-5cd0f75c1bcd/attachment.md","path":"templates/annotations.md","size":9964,"sha256":"0bc79d5d9dec608898b92160f2b3739a6a76ebdcf2f02fe3bb8c6f0ebc4fc8fc","contentType":"text/markdown; charset=utf-8"},{"id":"522e7209-b080-55ce-a940-f350eb23c0f1","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/522e7209-b080-55ce-a940-f350eb23c0f1/attachment.md","path":"templates/output-json.md","size":6275,"sha256":"af143f030a946b35c88cef657e4d5e8c28ec0c820db649a186360287e652dfc7","contentType":"text/markdown; charset=utf-8"},{"id":"1641a742-5852-55e6-974e-6c378be6487c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1641a742-5852-55e6-974e-6c378be6487c/attachment.md","path":"templates/output-markdown.md","size":6719,"sha256":"357313ac864233d0e1c9845bee135112806b65f8f159152bab8fc21eb80a8ba2","contentType":"text/markdown; charset=utf-8"},{"id":"fdeecfe1-cd2b-5925-b93f-ee0539ccdb98","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fdeecfe1-cd2b-5925-b93f-ee0539ccdb98/attachment.md","path":"workflows/analyze.md","size":5374,"sha256":"26fd0ee9ac655bb43c2b1be49b27dda6f9569256e87217aa232ba4928d8037b2","contentType":"text/markdown; charset=utf-8"},{"id":"f71242cd-014a-580b-b0d1-e6e6ea6c3210","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f71242cd-014a-580b-b0d1-e6e6ea6c3210/attachment.md","path":"workflows/cross-check.md","size":8170,"sha256":"611b927047d5a4894110174087e46a3f5c77bd489c58a509420043af6ce6f377","contentType":"text/markdown; charset=utf-8"},{"id":"5478c856-cb65-5379-bc12-bbd9c4cf39b2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5478c856-cb65-5379-bc12-bbd9c4cf39b2/attachment.md","path":"workflows/monitor.md","size":5247,"sha256":"3f10f504145b501b2e5ed78bfa6512ac8a237ffd0193d911d630f08894c49fe0","contentType":"text/markdown; charset=utf-8"},{"id":"244cdbc8-08ca-5196-b951-5d0f4a0b8512","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/244cdbc8-08ca-5196-b951-5d0f4a0b8512/attachment.md","path":"workflows/visualize.md","size":5853,"sha256":"396d50e16b59977362248f9505c82c2562bb39c55f5531b8296664b83ef0db0d","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"f8f8a418305bb19aaa380a0883f380c8dc5838036e147cdf0e5b1cc9205f2111","attachment_count":20,"text_attachments":20,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/track-agri-hedge-fund-positioning/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"finance-legal-compliance","category_label":"Finance"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"finance-legal-compliance","import_tag":"clean-skills-v1","description":"用 COT 非商業部位變化,量化對沖基金在農產品期貨的資金流向,並把出口需求、USDA 數據、美元/原油/金屬等宏觀風向整合成可交易的敘事與訊號。"}},"renderedAt":1782981915976}

<essential principles <principle name="cot as flow proxy" COT 週資料作為資金流代理 CFTC Commitments of Traders 報告是追蹤對沖基金農產品部位的核心資料: - 截止日 :每週二收盤 - 發布日 :每週五下午 3:30 ET - 交易者分類 :非商業(投機/基金)、商業(避險)、非報告 資金流 = 本週淨部位 - 上週淨部位(以合約口數計) </principle <principle name="group aggregation" 分組彙總邏輯 使用 CFTC 原生分組(commodity subgroup name): | 群組 | CFTC 分組名稱 | 包含商品 | |----------|-------------------------|-----------------------------------| | Grains | GRAINS | Corn, Wheat (SRW/HRW/HRS), Oats | | Oilseeds | OILSEED and PRODUCTS | Soybeans, Soybean Oil/Meal, Canola| | Meats | LIVESTOCK/MEAT PRODUCTS | Live Cattle, Lean Hogs, Fee…