切换主题
03. 交易数据模型:别让复盘建立在一段散文上
上一章练习参考答案
第一题,应该先轻量承接情绪,再抽取交易事实。复盘教练可以说“先把这笔训练样本拆开看”,但不能被情绪带走。真正进入分析前,必须拿到计划、入场、止损、止盈、退出和截图备注。
第二题,稳定代码适合处理边界判断、数据读取、风险计算、状态分支、权限和审计。大模型适合生成复盘表达、归纳训练问题、把证据组织成可读报告。
第三题,系统提示词不要散落在 Controller。可以放在 Agent 配置类,或者放在专门的 Prompt/AgentFactory 中,并通过测试固定关键边界句。
新问题:只靠用户描述会乱
上一章有了 ReviewCoachAgent。可是用户真的会按你想的格式输入吗?
他可能这样写:
“我看到突破就追了,后面被打掉,感觉很烦。”
这句话能复盘吗?勉强可以,但风险很大。你不知道入场价、止损价、止盈计划、方向、周期,也不知道他原本想练什么。模型如果硬复盘,就会靠想象补齐事实。
所以第三章要引入交易数据模型。复盘不能只读一段散文,必须有结构化交易记录。
TradeRecord
伴生工程里的交易模型是:
java
public record TradeRecord(
String tradeId,
String symbol,
String timeframe,
String direction,
double entryPrice,
Double stopLoss,
Double takeProfit,
double exitPrice,
String plannedSetup,
String entryReason,
String screenshotNotes
) {
boolean hasRiskPlan() {
return stopLoss != null && takeProfit != null;
}
}这里故意让 stopLoss 和 takeProfit 用 Double,而不是 double。因为真实业务里它们可能缺失。缺失不是 0,缺失就是没提供。
如果你把缺失当成 0,风险计算会变得很危险:系统看起来算出了结果,实际上是在用假数据复盘。
模拟仓库
第一版用内存仓库模拟数据库:
java
@Repository
public class InMemoryTradeRepository implements TradeRepository {
private final Map<String, TradeRecord> trades = Map.of(
"T-1001", new TradeRecord(...),
"T-2001", new TradeRecord(...)
);
public Optional<TradeRecord> findById(String tradeId) {
return Optional.ofNullable(trades.get(tradeId));
}
}T-1001 是一笔信息完整的训练交易。T-2001 故意缺少止损和止盈,用来模拟信息不足。
为什么模型要早建
很多 AI 项目一开始会偷懒:先把用户输入整段丢给模型,等效果不好再补结构化字段。
这会让后面很难改。因为你无法区分:
- 是用户没给数据?
- 是模型没理解?
- 是提示词没写好?
- 是工具没返回?
有了 TradeRecord,系统至少知道“事实字段”在哪里。模型只负责解释事实,不负责发明事实。
本章效果
调用完整交易:
json
{
"tradeId": "T-1001",
"includeKline": true,
"question": "复盘这笔训练交易"
}系统进入 REVIEWED。
调用信息不足的交易:
json
{
"tradeId": "T-2001",
"includeKline": false,
"question": "只知道我追了突破,帮我复盘"
}系统不能假装能复盘,后面第十二章会把它正式做成中断恢复。
这一章真正解决了什么
交易数据模型解决的是复盘的“事实地基”。
教练可以有表达风格,但事实不能靠猜。只要事实缺失,系统就应该进入追问或中断,而不是编一个看似专业的结论。
练习题
stopLoss缺失时,系统应该返回REVIEWED还是NEEDS_MORE_CONTEXT?plannedSetup和entryReason有什么区别?- 如果用户上传截图,你会把截图原图、截图 OCR 文字、人工备注分别放在哪里?