$npx -y skills add agiprolabs/claude-trading-skills --skill trade-journalStructured trade logging, performance review, behavioral pattern detection, and strategy attribution for systematic improvement
| 1 | # Trade Journal |
| 2 | |
| 3 | 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. |
| 4 | |
| 5 | ## Why Journaling Matters |
| 6 | |
| 7 | Most traders fail not from bad strategies but from bad behavior. A trade journal transforms subjective "feel" into objective data: |
| 8 | |
| 9 | - **Strategy Attribution**: Know which setups actually make money vs. which feel profitable |
| 10 | - **Behavioral Detection**: Catch revenge trading, FOMO entries, and premature exits before they compound |
| 11 | - **Pattern Recognition**: Discover that your Monday morning trades lose money, or that you cut SOL winners too early |
| 12 | - **Accountability**: Written rationale before entry forces deliberate decision-making |
| 13 | - **Improvement Tracking**: Measure whether changes to your process actually improve results |
| 14 | |
| 15 | Without a journal, you optimize on noise. With one, you optimize on signal. |
| 16 | |
| 17 | ## Trade Record Structure |
| 18 | |
| 19 | Every trade record captures context at entry and outcome at exit. See `references/record_format.md` for the complete 18-field schema. |
| 20 | |
| 21 | ### Minimum Required Fields |
| 22 | |
| 23 | ```python |
| 24 | trade = { |
| 25 | "id": "T-20250310-001", |
| 26 | "token": "SOL", |
| 27 | "direction": "long", |
| 28 | "entry_date": "2025-03-10T14:30:00Z", |
| 29 | "entry_price": 142.50, |
| 30 | "size_sol": 5.0, |
| 31 | "strategy": "momentum-breakout", |
| 32 | "rationale": "Breaking above 4h resistance at 141.80 with volume confirmation", |
| 33 | "exit_date": "2025-03-10T16:45:00Z", |
| 34 | "exit_price": 146.20, |
| 35 | "pnl_sol": 0.648, |
| 36 | "outcome": "win", |
| 37 | "lessons": "Held through initial pullback to 143.0, rewarded for patience" |
| 38 | } |
| 39 | ``` |
| 40 | |
| 41 | ### Strategy Tagging |
| 42 | |
| 43 | Use consistent tags to enable performance attribution: |
| 44 | |
| 45 | | Category | Tags | |
| 46 | |----------|------| |
| 47 | | Momentum | `momentum-breakout`, `trend-continuation`, `pullback-entry` | |
| 48 | | Mean Reversion | `range-fade`, `oversold-bounce`, `deviation-snap` | |
| 49 | | Event-Driven | `listing-play`, `catalyst-trade`, `news-reaction` | |
| 50 | | On-Chain | `whale-follow`, `wallet-copy`, `flow-signal` | |
| 51 | | DeFi | `lp-entry`, `yield-farm`, `arb-capture` | |
| 52 | |
| 53 | ### Rationale Templates |
| 54 | |
| 55 | Write rationale **before** entering. Templates by setup type: |
| 56 | |
| 57 | ``` |
| 58 | Momentum: "[Token] breaking [level] on [timeframe] with [confirmation]. Target [price], stop [price]." |
| 59 | Mean Reversion: "[Token] at [X] std devs from [mean] on [timeframe]. Expecting reversion to [target]." |
| 60 | On-Chain: "[Signal type] detected — [wallet/flow description]. Historical hit rate [X]%." |
| 61 | ``` |
| 62 | |
| 63 | ## Storage Format |
| 64 | |
| 65 | The journal uses JSON for structured querying and CSV for spreadsheet compatibility. |
| 66 | |
| 67 | ### JSON Format (Primary) |
| 68 | |
| 69 | ```json |
| 70 | { |
| 71 | "journal_version": "1.0", |
| 72 | "trader_id": "anon", |
| 73 | "trades": [ |
| 74 | { |
| 75 | "id": "T-20250310-001", |
| 76 | "token": "SOL", |
| 77 | "direction": "long", |
| 78 | "entry_date": "2025-03-10T14:30:00Z", |
| 79 | "entry_price": 142.50, |
| 80 | "size_sol": 5.0, |
| 81 | "size_usd": 712.50, |
| 82 | "strategy": "momentum-breakout", |
| 83 | "setup_quality": 8, |
| 84 | "rationale": "Breaking above 4h resistance with volume", |
| 85 | "exit_date": "2025-03-10T16:45:00Z", |
| 86 | "exit_price": 146.20, |
| 87 | "pnl_sol": 0.648, |
| 88 | "pnl_pct": 2.60, |
| 89 | "outcome": "win", |
| 90 | "hold_time_minutes": 135, |
| 91 | "emotional_state": "calm", |
| 92 | "lessons": "Patience through pullback paid off", |
| 93 | "tags": ["high-conviction", "clean-setup"] |
| 94 | } |
| 95 | ] |
| 96 | } |
| 97 | ``` |
| 98 | |
| 99 | ### CSV Format (Export) |
| 100 | |
| 101 | ``` |
| 102 | id,token,direction,entry_date,entry_price,size_sol,strategy,exit_date,exit_price,pnl_sol,pnl_pct,outcome,lessons |
| 103 | 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" |
| 104 | ``` |
| 105 | |
| 106 | ## Analytics from Journal Data |
| 107 | |
| 108 | ### Win Rate by Strategy |
| 109 | |
| 110 | ```python |
| 111 | from collections import Counter |
| 112 | |
| 113 | def win_rate_by_strategy(trades: list[dict]) -> dict[str, float]: |
| 114 | """Compute win rate grouped by strategy tag.""" |
| 115 | strategy_outcomes: dict[str, list[str]] = {} |
| 116 | for t in trades: |
| 117 | strat = t["strategy"] |
| 118 | strategy_outcomes.setdefault(strat, []).append(t["outcome"]) |
| 119 | |
| 120 | return { |
| 121 | strat: outcomes.count("win") / len(outcomes) |
| 122 | for strat, outcomes in strategy_outcomes.items() |
| 123 | if len(outcomes) >= 5 # minimum sample size |
| 124 | } |
| 125 | ``` |
| 126 | |
| 127 | ### Performance by Time of Day |
| 128 | |
| 129 | ```python |
| 130 | from datetime import datetime |
| 131 | |
| 132 | def pnl_by_hour(trades: list[dict]) -> dict[int, float]: |
| 133 | """Aggregate P&L by entry hour (UTC).""" |
| 134 | hourly: dict[int, float] = {} |
| 135 | for t in trades: |
| 136 | hour = datetime.fromisoformat(t["entry_date"].rstrip("Z")).hour |
| 137 | hourly[hour] = hourly.get(hour, 0.0) + t.get("pnl_sol", 0.0) |
| 138 | return dict(sorted(hourly.items())) |
| 139 | ``` |
| 140 | |
| 141 | ### Profit Factor by Token Type |
| 142 | |
| 143 | ```python |
| 144 | def profit_factor(trades: list[dict], group_key: str = "token") -> dict[str, float]: |
| 145 | """Compute profit factor (gross wins / gross losses) |