Add per-agent skill workspaces and TraderView management

This commit is contained in:
2026-03-17 13:55:14 +08:00
parent 1f5ee3698e
commit 2daf5717ba
35 changed files with 4774 additions and 331 deletions

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -1,21 +1,22 @@
---
name: fundamental_review
description: Review a company from a fundamentals-first perspective before issuing a trading signal.
name: 基本面分析
description: 当用户要求“基本面分析”“看财务质量”“分析盈利能力”“判断公司质量”或“评估长期盈利韧性”时,应使用此技能。
version: 1.0.0
---
# Fundamental Review
# 基本面分析
Use this skill when the task requires judging business quality, balance-sheet strength, profitability, or long-term earnings durability.
当用户希望从公司质量、资产负债表强度、盈利能力或长期盈利韧性出发判断标的时,使用这个技能。
## Workflow
## 工作流程
1. Check profitability, growth, financial health, and efficiency before forming a conclusion.
2. Separate durable business quality from short-term noise.
3. State what would invalidate the thesis.
4. End with a clear signal, confidence, and the main drivers behind that signal.
1. 在形成结论前,先检查盈利能力、成长性、财务健康度和经营效率。
2. 区分可持续的业务质量和短期噪音。
3. 明确指出会推翻当前判断的条件。
4. 最终给出清晰的信号、置信度和主要驱动因素。
## Guardrails
## 约束
- Do not rely on one metric in isolation.
- Call out missing data explicitly.
- Prefer conservative conclusions when financial quality is mixed.
- 不要孤立依赖单一指标。
- 缺失数据要明确指出。
- 当财务质量优劣混杂时,优先给出保守结论。

View File

@@ -1,21 +1,22 @@
---
name: portfolio_decisioning
description: Synthesize analyst inputs and risk feedback into explicit portfolio decisions.
name: 组合决策
description: 当用户要求“组合决策”“给出最终仓位”“整合分析结论”“输出交易决策”或“形成组合操作方案”时,应使用此技能。
version: 1.0.0
---
# Portfolio Decisioning
# 组合决策
Use this skill when you are responsible for converting team analysis into final trades.
当用户需要把团队分析转化为最终交易决策时,使用这个技能。
## Workflow
## 工作流程
1. Read analyst conclusions and risk warnings before acting.
2. Evaluate the current portfolio, cash, and margin constraints.
3. Record one explicit decision per ticker using the decision tool.
4. Summarize the portfolio-level rationale after all decisions are recorded.
1. 行动前先阅读分析师结论和风险警示。
2. 评估当前组合、现金和保证金约束。
3. 使用决策工具为每个 ticker 记录一个明确决策。
4. 在全部决策记录完成后,总结组合层面的整体理由。
## Guardrails
## 约束
- Position sizing must respect capital and margin limits.
- Prefer smaller size when analyst conviction and risk signals disagree.
- Do not leave a ticker undecided when the task expects a full slate of decisions.
- 仓位大小必须遵守资金和保证金限制。
- 当分析师信心与风险信号不一致时,优先采用更小仓位。
- 当任务要求完整决策清单时,不要让任何 ticker 处于未决状态。

View File

@@ -1,21 +1,22 @@
---
name: risk_review
description: Assess portfolio and market risks before final position sizing and execution.
name: 风险审查
description: 当用户要求“风险审查”“看组合风险”“检查集中度”“评估波动风险”或“确认仓位风险边界”时,应使用此技能。
version: 1.0.0
---
# Risk Review
# 风险审查
Use this skill when you must identify concentration, volatility, leverage, and scenario risks.
当用户需要识别集中度、波动率、杠杆和情景风险时,使用这个技能。
## Workflow
## 工作流程
1. Review the proposed exposure by ticker and theme.
2. Identify concentration, volatility, liquidity, and leverage concerns.
3. Rank warnings by severity.
4. Translate risk findings into concrete limits or cautions for the portfolio manager.
1. 按 ticker 和主题检查拟议敞口。
2. 识别集中度、波动率、流动性和杠杆方面的风险点。
3. 按严重程度排序风险警示。
4. 将风险结论转化为给投资经理的具体限制或注意事项。
## Guardrails
## 约束
- Focus on actionable risk controls.
- Quantify limits when the available data supports it.
- Distinguish fatal blockers from manageable risks.
- 聚焦可执行的风险控制措施。
- 当数据支持时尽量量化限制。
- 明确区分致命阻断项和可管理风险。

View File

@@ -1,21 +1,22 @@
---
name: sentiment_review
description: Analyze news flow, market psychology, and insider behavior for catalyst-driven signals.
name: 情绪分析
description: 当用户要求“情绪分析”“看新闻情绪”“分析市场心理”“判断事件驱动信号”或“检查内幕行为”时,应使用此技能。
version: 1.0.0
---
# Sentiment Review
# 情绪分析
Use this skill when the task depends on recent catalysts, news tone, or behavioral market signals.
当用户需要基于近期催化剂、新闻语气或行为层面的市场信号做判断时,使用这个技能。
## Workflow
## 工作流程
1. Review recent news and identify the dominant narrative.
2. Check insider activity for confirming or conflicting signals.
3. Separate durable sentiment shifts from transient noise.
4. Explain how sentiment changes the near-term trade outlook.
1. 回顾近期新闻并识别主导叙事。
2. 检查内幕活动,寻找确认或冲突信号。
3. 区分可持续的情绪变化和短暂噪音。
4. 说明情绪如何改变短期交易展望。
## Guardrails
## 约束
- Do not confuse attention with conviction.
- Highlight when sentiment is strong but unsupported by fundamentals.
- Be explicit about catalyst timing risk.
- 不要把注意力误判为真实信念。
- 当情绪很强但缺乏基本面支持时,要明确指出。
- 对催化剂时间窗口风险要说清楚。

View File

@@ -1,21 +1,22 @@
---
name: technical_review
description: Evaluate price action, momentum, and volatility to judge timing and market regime.
name: 技术分析
description: 当用户要求“技术分析”“看走势”“判断入场时机”“分析动量”“评估波动率”或“判断市场状态”时,应使用此技能。
version: 1.0.0
---
# Technical Review
# 技术分析
Use this skill when the task is sensitive to entry timing, trend quality, or short-term market structure.
当用户需要从入场时机、趋势质量或短期市场结构出发判断标的时,使用这个技能。
## Workflow
## 工作流程
1. Assess trend direction and strength.
2. Check momentum and mean-reversion conditions.
3. Review volatility before making aggressive recommendations.
4. Convert the setup into a trading view with explicit risk awareness.
1. 评估趋势方向和强度。
2. 检查动量与均值回归条件。
3. 在给出激进建议前先审视波动率。
4. 将当前形态转化为带有明确风险意识的交易观点。
## Guardrails
## 约束
- Distinguish trend continuation from overshoot.
- Avoid strong conviction when signals conflict.
- Treat volatility as a sizing input, not only a directional input.
- 区分趋势延续和过度透支。
- 当信号冲突时避免给出高确定性判断。
- 将波动率视为仓位输入,而不仅仅是方向输入。

View File

@@ -1,21 +1,31 @@
---
name: valuation_review
description: Estimate fair value and margin of safety using multiple valuation lenses.
name: 估值分析
description: 当用户要求“估值分析”“看合理价值”“判断高估低估”“测算安全边际”或“比较多种估值方法”时,应使用此技能。
version: 1.0.0
---
# Valuation Review
# 估值分析
Use this skill when the task requires determining whether a stock is cheap, expensive, or fairly priced.
当用户需要判断一只股票是低估、高估还是定价合理时,使用这个技能。
## Workflow
## 工作流程
1. Use more than one valuation method when possible.
2. Compare intrinsic value estimates with current market pricing.
3. Explain the key assumptions behind the valuation view.
4. State the margin of safety and what could compress or expand it.
1. 条件允许时,使用不止一种估值方法。
2. 对比内在价值估计与当前市场价格。
3. 解释估值判断背后的关键假设。
4. 明确安全边际,以及哪些因素会压缩或扩大它。
## Guardrails
## 可复用资源
- Treat valuation as a range, not a single precise number.
- Call out assumption sensitivity.
- Avoid high-confidence calls when inputs are sparse or unstable.
- `scripts/dcf_report.py`
用于贴现现金流估值的确定性计算和报告生成。
- `scripts/owner_earnings_report.py`
用于 owner earnings 估值的确定性计算和报告生成。
- `scripts/multiple_valuation_report.py`
用于 EV/EBITDA 和 Residual Income 两类估值报告生成。
## 约束
- 将估值视为区间,而不是一个精确点值。
- 明确说明假设敏感性。
- 当输入稀疏或不稳定时,避免给出高置信度判断。

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Deterministic DCF report helpers for the valuation_review skill."""
from __future__ import annotations
import json
from typing import Iterable
def build_dcf_report(rows: Iterable[dict], current_date: str) -> str:
"""Render a DCF valuation report from normalized row inputs."""
lines = [f"=== DCF Valuation Analysis ({current_date}) ===\n"]
for row in rows:
error = row.get("error")
ticker = row["ticker"]
if error:
lines.append(f"{ticker}: {error}\n")
continue
current_fcf = float(row["current_fcf"])
growth_rate = float(row["growth_rate"])
market_cap = float(row["market_cap"])
discount_rate = float(row.get("discount_rate", 0.10))
terminal_growth = float(row.get("terminal_growth", 0.03))
num_years = int(row.get("num_years", 5))
pv_fcf = sum(
current_fcf
* (1 + growth_rate) ** year
/ (1 + discount_rate) ** year
for year in range(1, num_years + 1)
)
terminal_fcf = (
current_fcf
* (1 + growth_rate) ** num_years
* (1 + terminal_growth)
)
terminal_value = terminal_fcf / (discount_rate - terminal_growth)
pv_terminal = terminal_value / (1 + discount_rate) ** num_years
enterprise_value = pv_fcf + pv_terminal
value_gap = (enterprise_value - market_cap) / market_cap * 100
if value_gap > 20:
assessment = "SIGNIFICANTLY UNDERVALUED"
elif value_gap > 0:
assessment = "POTENTIALLY UNDERVALUED"
elif value_gap > -20:
assessment = "POTENTIALLY OVERVALUED"
else:
assessment = "SIGNIFICANTLY OVERVALUED"
lines.append(f"{ticker}:")
lines.append(f" Current FCF: ${current_fcf:,.0f}")
lines.append(f" DCF Enterprise Value: ${enterprise_value:,.0f}")
lines.append(f" Market Cap: ${market_cap:,.0f}")
lines.append(f" Value Gap: {value_gap:+.1f}% -> {assessment}")
lines.append("")
return "\n".join(lines)
def main() -> None:
"""Read normalized rows from stdin and emit a text report."""
payload = json.load(__import__("sys").stdin)
print(build_dcf_report(payload["rows"], payload["current_date"]))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,115 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Deterministic multiple-based valuation helpers for the valuation_review skill."""
from __future__ import annotations
import json
from typing import Iterable
def build_ev_ebitda_report(rows: Iterable[dict], current_date: str) -> str:
"""Render an EV/EBITDA valuation report from normalized row inputs."""
lines = [f"=== EV/EBITDA Valuation ({current_date}) ===\n"]
for row in rows:
error = row.get("error")
ticker = row["ticker"]
if error:
lines.append(f"{ticker}: {error}\n")
continue
current_multiple = float(row["current_multiple"])
median_multiple = float(row["median_multiple"])
current_ebitda = float(row["current_ebitda"])
market_cap = float(row["market_cap"])
net_debt = float(row["net_debt"])
implied_ev = median_multiple * current_ebitda
implied_equity = max(implied_ev - net_debt, 0.0)
value_gap = (
(implied_equity - market_cap) / market_cap * 100
if market_cap > 0
else 0.0
)
multiple_discount = (
(median_multiple - current_multiple) / median_multiple * 100
)
if multiple_discount > 10:
assessment = "TRADING BELOW HISTORICAL MULTIPLE"
elif multiple_discount > -10:
assessment = "NEAR HISTORICAL AVERAGE"
else:
assessment = "TRADING ABOVE HISTORICAL MULTIPLE"
lines.append(f"{ticker}:")
lines.append(f" Current EV/EBITDA: {current_multiple:.1f}x")
lines.append(f" Historical Median: {median_multiple:.1f}x")
lines.append(f" Multiple vs History: {multiple_discount:+.1f}%")
lines.append(f" Implied Equity Value: ${implied_equity:,.0f}")
lines.append(f" Value Gap: {value_gap:+.1f}% -> {assessment}")
lines.append("")
return "\n".join(lines)
def build_residual_income_report(rows: Iterable[dict], current_date: str) -> str:
"""Render a residual income valuation report from normalized row inputs."""
lines = [f"=== Residual Income Valuation ({current_date}) ===\n"]
for row in rows:
error = row.get("error")
ticker = row["ticker"]
if error:
lines.append(f"{ticker}: {error}\n")
continue
book_value = float(row["book_value"])
initial_ri = float(row["initial_ri"])
market_cap = float(row["market_cap"])
cost_of_equity = float(row.get("cost_of_equity", 0.10))
bv_growth = float(row.get("bv_growth", 0.03))
terminal_growth = float(row.get("terminal_growth", 0.03))
num_years = int(row.get("num_years", 5))
margin_of_safety = float(row.get("margin_of_safety", 0.20))
pv_ri = sum(
initial_ri * (1 + bv_growth) ** year / (1 + cost_of_equity) ** year
for year in range(1, num_years + 1)
)
terminal_ri = initial_ri * (1 + bv_growth) ** (num_years + 1)
terminal_value = terminal_ri / (cost_of_equity - terminal_growth)
pv_terminal = terminal_value / (1 + cost_of_equity) ** num_years
intrinsic_value = (book_value + pv_ri + pv_terminal) * (
1 - margin_of_safety
)
value_gap = (intrinsic_value - market_cap) / market_cap * 100
lines.append(f"{ticker}:")
lines.append(f" Book Value: ${book_value:,.0f}")
lines.append(f" Residual Income: ${initial_ri:,.0f}")
lines.append(
f" Intrinsic Value (w/ 20% MoS): ${intrinsic_value:,.0f}",
)
lines.append(f" Value Gap: {value_gap:+.1f}%")
lines.append("")
return "\n".join(lines)
def main() -> None:
"""Read normalized rows from stdin and emit one selected text report."""
payload = json.load(__import__("sys").stdin)
mode = payload["mode"]
if mode == "ev_ebitda":
print(build_ev_ebitda_report(payload["rows"], payload["current_date"]))
return
if mode == "residual_income":
print(build_residual_income_report(payload["rows"], payload["current_date"]))
return
raise ValueError(f"Unsupported mode: {mode}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Deterministic owner earnings valuation helpers for the valuation_review skill."""
from __future__ import annotations
import json
from typing import Iterable
def build_owner_earnings_report(rows: Iterable[dict], current_date: str) -> str:
"""Render an owner earnings valuation report from normalized row inputs."""
lines = [f"=== Owner Earnings Valuation ({current_date}) ===\n"]
for row in rows:
error = row.get("error")
ticker = row["ticker"]
if error:
lines.append(f"{ticker}: {error}\n")
continue
owner_earnings = float(row["owner_earnings"])
growth_rate = float(row["growth_rate"])
market_cap = float(row["market_cap"])
required_return = float(row.get("required_return", 0.15))
margin_of_safety = float(row.get("margin_of_safety", 0.25))
num_years = int(row.get("num_years", 5))
pv_earnings = sum(
owner_earnings
* (1 + growth_rate) ** year
/ (1 + required_return) ** year
for year in range(1, num_years + 1)
)
terminal_growth = min(growth_rate, 0.03)
terminal_earnings = (
owner_earnings
* (1 + growth_rate) ** num_years
* (1 + terminal_growth)
)
terminal_value = terminal_earnings / (
required_return - terminal_growth
)
pv_terminal = terminal_value / (1 + required_return) ** num_years
intrinsic_value = (pv_earnings + pv_terminal) * (1 - margin_of_safety)
value_gap = (intrinsic_value - market_cap) / market_cap * 100
if value_gap > 20:
assessment = "SIGNIFICANTLY UNDERVALUED"
elif value_gap > 0:
assessment = "POTENTIALLY UNDERVALUED"
elif value_gap > -20:
assessment = "POTENTIALLY OVERVALUED"
else:
assessment = "SIGNIFICANTLY OVERVALUED"
lines.append(f"{ticker}:")
lines.append(f" Owner Earnings: ${owner_earnings:,.0f}")
lines.append(
f" Intrinsic Value (w/ 25% MoS): ${intrinsic_value:,.0f}",
)
lines.append(f" Market Cap: ${market_cap:,.0f}")
lines.append(f" Value Gap: {value_gap:+.1f}% -> {assessment}")
lines.append("")
return "\n".join(lines)
def main() -> None:
"""Read normalized rows from stdin and emit a text report."""
payload = json.load(__import__("sys").stdin)
print(build_owner_earnings_report(payload["rows"], payload["current_date"]))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,21 @@
---
name: 组合决策
description: 整合分析师观点与风险反馈,形成明确的组合层决策。
---
# 组合决策
当你负责把团队分析转化为最终交易决策时,使用这个技能。
## 工作流程
1. 行动前先阅读分析师结论和风险警示。
2. 评估当前组合、现金和保证金约束。
3. 使用决策工具为每个 ticker 记录一个明确决策。
4. 在全部决策记录完成后,总结组合层面的整体理由。
## 约束
- 仓位大小必须遵守资金和保证金限制。
- 当分析师信心与风险信号不一致时,优先采用更小仓位。
- 当任务要求完整决策清单时,不要让任何 ticker 处于未决状态。

View File

@@ -0,0 +1,21 @@
---
name: 风险审查
description: 在最终仓位和执行前,评估组合与市场风险。
---
# 风险审查
当你需要识别集中度、波动率、杠杆和情景风险时,使用这个技能。
## 工作流程
1. 按 ticker 和主题检查拟议敞口。
2. 识别集中度、波动率、流动性和杠杆方面的风险点。
3. 按严重程度排序风险警示。
4. 将风险结论转化为给投资经理的具体限制或注意事项。
## 约束
- 聚焦可执行的风险控制措施。
- 当数据支持时尽量量化限制。
- 明确区分致命阻断项和可管理风险。

View File

@@ -0,0 +1,21 @@
---
name: 情绪分析
description: 分析新闻流、市场心理和内幕行为,识别事件驱动型信号。
---
# 情绪分析
当任务依赖近期催化剂、新闻语气或行为层面的市场信号时,使用这个技能。
## 工作流程
1. 回顾近期新闻并识别主导叙事。
2. 检查内幕活动,寻找确认或冲突信号。
3. 区分可持续的情绪变化和短暂噪音。
4. 说明情绪如何改变短期交易展望。
## 约束
- 不要把注意力误判为真实信念。
- 当情绪很强但缺乏基本面支持时,要明确指出。
- 对催化剂时间窗口风险要说清楚。

View File

@@ -0,0 +1,21 @@
---
name: 技术分析
description: 评估价格行为、动量和波动率,用于判断时机和市场状态。
---
# 技术分析
当任务对入场时机、趋势质量或短期市场结构敏感时,使用这个技能。
## 工作流程
1. 评估趋势方向和强度。
2. 检查动量与均值回归条件。
3. 在给出激进建议前先审视波动率。
4. 将当前形态转化为带有明确风险意识的交易观点。
## 约束
- 区分趋势延续和过度透支。
- 当信号冲突时避免给出高确定性判断。
- 将波动率视为仓位输入,而不仅仅是方向输入。

View File

@@ -0,0 +1,21 @@
---
name: 估值分析
description: 使用多种估值视角评估合理价值和安全边际。
---
# 估值分析
当任务需要判断一只股票是低估、高估还是定价合理时,使用这个技能。
## 工作流程
1. 条件允许时,使用不止一种估值方法。
2. 对比内在价值估计与当前市场价格。
3. 解释估值判断背后的关键假设。
4. 明确安全边际,以及哪些因素会压缩或扩大它。
## 约束
- 将估值视为区间,而不是一个精确点值。
- 明确说明假设敏感性。
- 当输入稀疏或不稳定时,避免给出高置信度判断。