trade-journal

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Trade Journal

交易日志

Structured trade journaling for systematic improvement. Log every trade with context, review performance at multiple cadences, detect behavioral patterns that destroy edge, and attribute returns to specific strategies.
用于系统化提升的结构化交易日志记录。记录每一笔交易的上下文信息,按不同周期复盘绩效,检测会削弱交易优势的行为模式,并将收益归因于特定策略。

Why Journaling Matters

交易日志的重要性

Most traders fail not from bad strategies but from bad behavior. A trade journal transforms subjective "feel" into objective data:
  • Strategy Attribution: Know which setups actually make money vs. which feel profitable
  • Behavioral Detection: Catch revenge trading, FOMO entries, and premature exits before they compound
  • Pattern Recognition: Discover that your Monday morning trades lose money, or that you cut SOL winners too early
  • Accountability: Written rationale before entry forces deliberate decision-making
  • Improvement Tracking: Measure whether changes to your process actually improve results
Without a journal, you optimize on noise. With one, you optimize on signal.
大多数交易者失败并非因为策略不佳,而是因为不良交易行为。交易日志能将主观的“感觉”转化为客观数据:
  • 策略归因:明确哪些交易定式真正盈利,哪些只是看似盈利
  • 行为检测:在报复性交易、FOMO入场、过早离场等行为加剧前及时发现
  • 模式识别:发现周一早盘交易总是亏损,或是过早止盈SOL交易等规律
  • 问责机制:入场前写下交易理由,促使决策更审慎
  • 提升追踪:衡量交易流程的调整是否真的改善了结果
没有日志,你只是在噪音中优化;有了日志,你才能在有效信号中优化。

Trade Record Structure

交易记录结构

Every trade record captures context at entry and outcome at exit. See
references/record_format.md
for the complete 18-field schema.
每一条交易记录都会捕捉入场时的上下文信息和离场时的结果。完整的18字段 schema 请查看
references/record_format.md

Minimum Required Fields

必填字段

python
trade = {
    "id": "T-20250310-001",
    "token": "SOL",
    "direction": "long",
    "entry_date": "2025-03-10T14:30:00Z",
    "entry_price": 142.50,
    "size_sol": 5.0,
    "strategy": "momentum-breakout",
    "rationale": "Breaking above 4h resistance at 141.80 with volume confirmation",
    "exit_date": "2025-03-10T16:45:00Z",
    "exit_price": 146.20,
    "pnl_sol": 0.648,
    "outcome": "win",
    "lessons": "Held through initial pullback to 143.0, rewarded for patience"
}
python
trade = {
    "id": "T-20250310-001",
    "token": "SOL",
    "direction": "long",
    "entry_date": "2025-03-10T14:30:00Z",
    "entry_price": 142.50,
    "size_sol": 5.0,
    "strategy": "momentum-breakout",
    "rationale": "Breaking above 4h resistance at 141.80 with volume confirmation",
    "exit_date": "2025-03-10T16:45:00Z",
    "exit_price": 146.20,
    "pnl_sol": 0.648,
    "outcome": "win",
    "lessons": "Held through initial pullback to 143.0, rewarded for patience"
}

Strategy Tagging

策略标签

Use consistent tags to enable performance attribution:
CategoryTags
Momentum
momentum-breakout
,
trend-continuation
,
pullback-entry
Mean Reversion
range-fade
,
oversold-bounce
,
deviation-snap
Event-Driven
listing-play
,
catalyst-trade
,
news-reaction
On-Chain
whale-follow
,
wallet-copy
,
flow-signal
DeFi
lp-entry
,
yield-farm
,
arb-capture
使用统一标签实现绩效归因:
分类标签
动量策略
momentum-breakout
,
trend-continuation
,
pullback-entry
均值回归
range-fade
,
oversold-bounce
,
deviation-snap
事件驱动
listing-play
,
catalyst-trade
,
news-reaction
链上数据
whale-follow
,
wallet-copy
,
flow-signal
DeFi
lp-entry
,
yield-farm
,
arb-capture

Rationale Templates

交易理由模板

Write rationale before entering. Templates by setup type:
Momentum: "[Token] breaking [level] on [timeframe] with [confirmation]. Target [price], stop [price]."
Mean Reversion: "[Token] at [X] std devs from [mean] on [timeframe]. Expecting reversion to [target]."
On-Chain: "[Signal type] detected — [wallet/flow description]. Historical hit rate [X]%."
入场前撰写交易理由。按定式类型分类的模板:
动量策略: "[Token] 在[时间周期]突破[价位],伴随[确认信号]。目标价[价格],止损价[价格]。"
均值回归: "[Token] 在[时间周期]偏离均值[X]个标准差。预期回归至[目标价]。"
链上数据: "检测到[信号类型] — [钱包/资金流描述]。历史命中率[X]%。"

Storage Format

存储格式

The journal uses JSON for structured querying and CSV for spreadsheet compatibility.
日志采用JSON格式支持结构化查询,同时提供CSV格式兼容电子表格。

JSON Format (Primary)

JSON格式(主格式)

json
{
  "journal_version": "1.0",
  "trader_id": "anon",
  "trades": [
    {
      "id": "T-20250310-001",
      "token": "SOL",
      "direction": "long",
      "entry_date": "2025-03-10T14:30:00Z",
      "entry_price": 142.50,
      "size_sol": 5.0,
      "size_usd": 712.50,
      "strategy": "momentum-breakout",
      "setup_quality": 8,
      "rationale": "Breaking above 4h resistance with volume",
      "exit_date": "2025-03-10T16:45:00Z",
      "exit_price": 146.20,
      "pnl_sol": 0.648,
      "pnl_pct": 2.60,
      "outcome": "win",
      "hold_time_minutes": 135,
      "emotional_state": "calm",
      "lessons": "Patience through pullback paid off",
      "tags": ["high-conviction", "clean-setup"]
    }
  ]
}
json
{
  "journal_version": "1.0",
  "trader_id": "anon",
  "trades": [
    {
      "id": "T-20250310-001",
      "token": "SOL",
      "direction": "long",
      "entry_date": "2025-03-10T14:30:00Z",
      "entry_price": 142.50,
      "size_sol": 5.0,
      "size_usd": 712.50,
      "strategy": "momentum-breakout",
      "setup_quality": 8,
      "rationale": "Breaking above 4h resistance with volume",
      "exit_date": "2025-03-10T16:45:00Z",
      "exit_price": 146.20,
      "pnl_sol": 0.648,
      "pnl_pct": 2.60,
      "outcome": "win",
      "hold_time_minutes": 135,
      "emotional_state": "calm",
      "lessons": "Patience through pullback paid off",
      "tags": ["high-conviction", "clean-setup"]
    }
  ]
}

CSV Format (Export)

CSV格式(导出用)

id,token,direction,entry_date,entry_price,size_sol,strategy,exit_date,exit_price,pnl_sol,pnl_pct,outcome,lessons
T-20250310-001,SOL,long,2025-03-10T14:30:00Z,142.50,5.0,momentum-breakout,2025-03-10T16:45:00Z,146.20,0.648,2.60,win,"Patience paid off"
id,token,direction,entry_date,entry_price,size_sol,strategy,exit_date,exit_price,pnl_sol,pnl_pct,outcome,lessons
T-20250310-001,SOL,long,2025-03-10T14:30:00Z,142.50,5.0,momentum-breakout,2025-03-10T16:45:00Z,146.20,0.648,2.60,win,"Patience paid off"

Analytics from Journal Data

日志数据的分析应用

Win Rate by Strategy

按策略统计胜率

python
from collections import Counter

def win_rate_by_strategy(trades: list[dict]) -> dict[str, float]:
    """Compute win rate grouped by strategy tag."""
    strategy_outcomes: dict[str, list[str]] = {}
    for t in trades:
        strat = t["strategy"]
        strategy_outcomes.setdefault(strat, []).append(t["outcome"])

    return {
        strat: outcomes.count("win") / len(outcomes)
        for strat, outcomes in strategy_outcomes.items()
        if len(outcomes) >= 5  # minimum sample size
    }
python
from collections import Counter

def win_rate_by_strategy(trades: list[dict]) -> dict[str, float]:
    """Compute win rate grouped by strategy tag."""
    strategy_outcomes: dict[str, list[str]] = {}
    for t in trades:
        strat = t["strategy"]
        strategy_outcomes.setdefault(strat, []).append(t["outcome"])

    return {
        strat: outcomes.count("win") / len(outcomes)
        for strat, outcomes in strategy_outcomes.items()
        if len(outcomes) >= 5  # minimum sample size
    }

Performance by Time of Day

按时段统计绩效

python
from datetime import datetime

def pnl_by_hour(trades: list[dict]) -> dict[int, float]:
    """Aggregate P&L by entry hour (UTC)."""
    hourly: dict[int, float] = {}
    for t in trades:
        hour = datetime.fromisoformat(t["entry_date"].rstrip("Z")).hour
        hourly[hour] = hourly.get(hour, 0.0) + t.get("pnl_sol", 0.0)
    return dict(sorted(hourly.items()))
python
from datetime import datetime

def pnl_by_hour(trades: list[dict]) -> dict[int, float]:
    """Aggregate P&L by entry hour (UTC)."""
    hourly: dict[int, float] = {}
    for t in trades:
        hour = datetime.fromisoformat(t["entry_date"].rstrip("Z")).hour
        hourly[hour] = hourly.get(hour, 0.0) + t.get("pnl_sol", 0.0)
    return dict(sorted(hourly.items()))

Profit Factor by Token Type

按代币类型统计盈利因子

python
def profit_factor(trades: list[dict], group_key: str = "token") -> dict[str, float]:
    """Compute profit factor (gross wins / gross losses) by grouping key."""
    groups: dict[str, dict[str, float]] = {}
    for t in trades:
        key = t.get(group_key, "unknown")
        groups.setdefault(key, {"wins": 0.0, "losses": 0.0})
        pnl = t.get("pnl_sol", 0.0)
        if pnl > 0:
            groups[key]["wins"] += pnl
        else:
            groups[key]["losses"] += abs(pnl)

    return {
        k: v["wins"] / v["losses"] if v["losses"] > 0 else float("inf")
        for k, v in groups.items()
    }
python
def profit_factor(trades: list[dict], group_key: str = "token") -> dict[str, float]:
    """Compute profit factor (gross wins / gross losses) by grouping key."""
    groups: dict[str, dict[str, float]] = {}
    for t in trades:
        key = t.get(group_key, "unknown")
        groups.setdefault(key, {"wins": 0.0, "losses": 0.0})
        pnl = t.get("pnl_sol", 0.0)
        if pnl > 0:
            groups[key]["wins"] += pnl
        else:
            groups[key]["losses"] += abs(pnl)

    return {
        k: v["wins"] / v["losses"] if v["losses"] > 0 else float("inf")
        for k, v in groups.items()
    }

Behavioral Pattern Detection

行为模式检测

The journal enables detection of destructive trading patterns. See
references/review_framework.md
for the full framework.
交易日志可用于检测破坏性交易模式。完整框架请查看
references/review_framework.md

Revenge Trading

报复性交易

Rapid re-entry after a loss, often with larger size:
python
def detect_revenge_trades(trades: list[dict], max_gap_minutes: int = 15) -> list[dict]:
    """Find trades entered within max_gap_minutes of a losing exit."""
    sorted_trades = sorted(trades, key=lambda t: t["entry_date"])
    revenge = []
    for i in range(1, len(sorted_trades)):
        prev, curr = sorted_trades[i - 1], sorted_trades[i]
        if prev["outcome"] == "loss":
            prev_exit = datetime.fromisoformat(prev["exit_date"].rstrip("Z"))
            curr_entry = datetime.fromisoformat(curr["entry_date"].rstrip("Z"))
            gap = (curr_entry - prev_exit).total_seconds() / 60
            if gap <= max_gap_minutes:
                revenge.append(curr)
    return revenge
亏损后快速重新入场,通常仓位更大:
python
def detect_revenge_trades(trades: list[dict], max_gap_minutes: int = 15) -> list[dict]:
    """Find trades entered within max_gap_minutes of a losing exit."""
    sorted_trades = sorted(trades, key=lambda t: t["entry_date"])
    revenge = []
    for i in range(1, len(sorted_trades)):
        prev, curr = sorted_trades[i - 1], sorted_trades[i]
        if prev["outcome"] == "loss":
            prev_exit = datetime.fromisoformat(prev["exit_date"].rstrip("Z"))
            curr_entry = datetime.fromisoformat(curr["entry_date"].rstrip("Z"))
            gap = (curr_entry - prev_exit).total_seconds() / 60
            if gap <= max_gap_minutes:
                revenge.append(curr)
    return revenge

FOMO Detection

FOMO行为检测

Entering after large moves without proper setup:
  • Entry rationale is vague or missing
  • Setup quality self-rated below 5/10
  • Entry during a move that already exceeded 1 ATR
未按定式操作,在大幅波动后入场:
  • 入场理由模糊或缺失
  • 自我评定的定式质量低于5/10
  • 入场时波动已超过1个ATR

Cutting Winners / Riding Losers

过早止盈/扛单

python
def winner_loser_hold_times(trades: list[dict]) -> dict[str, float]:
    """Compare average hold time for wins vs losses."""
    win_times = [t["hold_time_minutes"] for t in trades if t["outcome"] == "win"]
    loss_times = [t["hold_time_minutes"] for t in trades if t["outcome"] == "loss"]
    return {
        "avg_win_hold_min": sum(win_times) / len(win_times) if win_times else 0,
        "avg_loss_hold_min": sum(loss_times) / len(loss_times) if loss_times else 0,
    }
    # RED FLAG: if avg_loss_hold > avg_win_hold, you're cutting winners and riding losers
python
def winner_loser_hold_times(trades: list[dict]) -> dict[str, float]:
    """Compare average hold time for wins vs losses."""
    win_times = [t["hold_time_minutes"] for t in trades if t["outcome"] == "win"]
    loss_times = [t["hold_time_minutes"] for t in trades if t["outcome"] == "loss"]
    return {
        "avg_win_hold_min": sum(win_times) / len(win_times) if win_times else 0,
        "avg_loss_hold_min": sum(loss_times) / len(loss_times) if loss_times else 0,
    }
    # 危险信号:如果avg_loss_hold > avg_win_hold,说明你在过早止盈、扛单亏损

Tilt Detection

情绪失控检测

Size escalation after losses suggests emotional trading:
python
def detect_tilt(trades: list[dict], threshold: float = 1.5) -> list[dict]:
    """Flag trades where size increased >threshold after a loss."""
    tilt_trades = []
    for i in range(1, len(trades)):
        prev, curr = trades[i - 1], trades[i]
        if prev["outcome"] == "loss" and curr["size_sol"] > prev["size_sol"] * threshold:
            tilt_trades.append(curr)
    return tilt_trades
亏损后仓位加大,表明交易受情绪影响:
python
def detect_tilt(trades: list[dict], threshold: float = 1.5) -> list[dict]:
    """Flag trades where size increased >threshold after a loss."""
    tilt_trades = []
    for i in range(1, len(trades)):
        prev, curr = trades[i - 1], trades[i]
        if prev["outcome"] == "loss" and curr["size_sol"] > prev["size_sol"] * threshold:
            tilt_trades.append(curr)
    return tilt_trades

Review Cadence

复盘周期

Daily Review (5 minutes)

每日复盘(5分钟)

  • How many trades today? P&L?
  • Did I follow my rules on every trade?
  • Any emotional decisions?
  • One thing I did well, one thing to improve
  • 今日交易数量?盈亏情况?
  • 每笔交易是否都遵守了规则?
  • 是否有情绪化决策?
  • 做得好的一点,以及需要改进的一点

Weekly Review (30 minutes)

每周复盘(30分钟)

  • Win rate and profit factor by strategy
  • Behavioral pattern check (revenge trades, tilt, FOMO)
  • Best and worst trade of the week — what made them different?
  • Strategy performance vs. expectations
  • Adjust position sizing if needed
  • 按策略统计胜率和盈利因子
  • 检查行为模式(报复性交易、情绪失控、FOMO)
  • 本周最佳和最差交易——差异在哪里?
  • 策略绩效与预期对比
  • 必要时调整仓位大小

Monthly Review (2 hours)

每月复盘(2小时)

  • Full strategy attribution analysis
  • Equity curve review — drawdown periods and recovery
  • Compare actual vs. planned risk per trade
  • Performance by token type, time of day, day of week
  • Are any strategies consistently losing? Consider dropping them
  • Review and update strategy parameters
See
references/review_framework.md
for detailed review checklists and questions.
  • 完整的策略归因分析
  • 权益曲线复盘——回撤期和复苏情况
  • 对比实际与计划的每笔交易风险
  • 按代币类型、时段、星期统计绩效
  • 是否有策略持续亏损?考虑放弃
  • 复盘并更新策略参数
详细的复盘清单和问题请查看
references/review_framework.md

Partial Exits and Scaled Entries

分批离场与分批入场

Real trading involves scaling in and out. The journal handles this with child records:
python
undefined
实际交易中会涉及分批入场和离场。日志通过子记录处理此类情况:
python
undefined

Parent trade with two scale-out exits

包含两次分批离场的父交易

parent = { "id": "T-20250310-001", "token": "BONK", "direction": "long", "entry_date": "2025-03-10T14:30:00Z", "entry_price": 0.000023, "size_sol": 10.0, "strategy": "momentum-breakout", "exits": [ {"date": "2025-03-10T15:00:00Z", "price": 0.000025, "size_pct": 50, "reason": "first-target"}, {"date": "2025-03-10T16:30:00Z", "price": 0.000028, "size_pct": 50, "reason": "trailing-stop"}, ] }

See `references/record_format.md` for full documentation of partial exit handling.
parent = { "id": "T-20250310-001", "token": "BONK", "direction": "long", "entry_date": "2025-03-10T14:30:00Z", "entry_price": 0.000023, "size_sol": 10.0, "strategy": "momentum-breakout", "exits": [ {"date": "2025-03-10T15:00:00Z", "price": 0.000025, "size_pct": 50, "reason": "first-target"}, {"date": "2025-03-10T16:30:00Z", "price": 0.000028, "size_pct": 50, "reason": "trailing-stop"}, ] }

分批离场的完整说明请查看 `references/record_format.md`。

Files

文件说明

References

参考文档

  • references/record_format.md
    — Complete 18-field trade record schema, field descriptions, tagging taxonomy, CSV/JSON examples, partial exit handling
  • references/review_framework.md
    — Daily/weekly/monthly review checklists, behavioral red flags, performance decay detection
  • references/record_format.md
    — 完整的18字段交易记录schema、字段说明、标签分类、CSV/JSON示例、分批离场处理方式
  • references/review_framework.md
    — 每日/每周/每月复盘清单、行为危险信号、绩效衰减检测

Scripts

脚本文件

  • scripts/trade_logger.py
    — CLI trade logger: add, list, update, compute stats, filter, demo mode (stdlib only)
  • scripts/journal_analyzer.py
    — Journal analysis: strategy performance, behavioral patterns, time-based analysis, demo mode (stdlib only)
  • scripts/trade_logger.py
    — CLI交易日志工具:添加、列出、更新交易,计算统计数据,筛选,演示模式(仅使用标准库)
  • scripts/journal_analyzer.py
    — 日志分析工具:策略绩效、行为模式、时段分析,演示模式(仅使用标准库)

Dependencies

依赖说明

Both scripts use Python standard library only (
json
,
datetime
,
argparse
,
collections
). No external packages required.
bash
undefined
两个脚本仅使用Python标准库(
json
,
datetime
,
argparse
,
collections
),无需外部包。
bash
undefined

No installation needed — stdlib only

无需安装——仅依赖标准库

python scripts/trade_logger.py --demo python scripts/journal_analyzer.py --demo
undefined
python scripts/trade_logger.py --demo python scripts/journal_analyzer.py --demo
undefined

Disclaimer

免责声明

This skill provides tools for trade record-keeping and performance analysis. It does not provide financial advice, trading recommendations, or guarantee any trading outcomes. All analysis is informational and for personal review purposes only.
本工具仅提供交易记录和绩效分析功能,不提供财务建议、交易推荐,也不保证任何交易结果。所有分析仅作信息参考,供个人复盘使用。