Skip to content

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;
    }
}

这里故意让 stopLosstakeProfitDouble,而不是 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": "只知道我追了突破,帮我复盘"
}

系统不能假装能复盘,后面第十二章会把它正式做成中断恢复。

这一章真正解决了什么

交易数据模型解决的是复盘的“事实地基”。

教练可以有表达风格,但事实不能靠猜。只要事实缺失,系统就应该进入追问或中断,而不是编一个看似专业的结论。

练习题

  1. stopLoss 缺失时,系统应该返回 REVIEWED 还是 NEEDS_MORE_CONTEXT
  2. plannedSetupentryReason 有什么区别?
  3. 如果用户上传截图,你会把截图原图、截图 OCR 文字、人工备注分别放在哪里?

Built with VitePress. Deployed on Cloudflare Pages.