Skip to content
Back to skills

Trade Journal Analytics

ASecurity

Complete trade journalling system: trade logging, performance analytics, streak analysis, drawdown tracking, tag drill-down, and report generation. USE FOR: trade journal, log trade, performance report, win rate, expectancy, R-multiple, drawdown, equity curve, streak, P&L, SQN, profit factor, trade analytics, journal, session breakdown.

  • 14 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 3, 2026
ai-agentspythongotestinggitperformance

Security analysis

A100/100

Scanned June 3, 2026

npx -y skills add mahmoud20138/Tradecraft --skill trade-journal-analytics --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Trade Journal Analytics?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Trade Journal Analytics
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mahmoud20138-trade-journal-analytics/badge)](https://www.skillsdirectory.com/skills/mahmoud20138-trade-journal-analytics)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: trade-journal-analytics
description: "Complete trade journalling system: trade logging, performance analytics, streak analysis, drawdown tracking, tag drill-down, and report generation. USE FOR: trade journal, log trade, performance report, win rate, expectancy, R-multiple, drawdown, equity curve, streak, P&L, SQN, profit factor, trade analytics, journal, session breakdown."
related_skills:
  - risk-and-portfolio
  - risk-and-portfolio
  - backtesting-sim
tags:
  - trading
  - infrastructure
  - journal
  - analytics
  - performance
  - review
skill_level: beginner
kind: reference
category: trading/psychology
status: active
---
> **Skill:** Trade Journal Analytics  |  **Domain:** trading  |  **Category:** infrastructure  |  **Level:** beginner
> **Tags:** `trading`, `infrastructure`, `journal`, `analytics`, `performance`, `review`


---

## Trade Journal & Analytics Skill

### Overview
A full-featured trade journalling and performance analysis system. Handles every step from
logging individual trades to generating publication-quality HTML/Markdown reports.
Built on pandas for fast aggregation and uses no external report dependencies.

### Python Module
`xtrading/skills/trade_journal.py`

### Stack
- **pandas** — DataFrame aggregation, groupby, pivot tables
- **numpy** — Equity curve, cumulative P&L, drawdown series
- **dataclasses** — Typed immutable `TradeRecord` structure
- **json / pathlib** — JSON persistence and cross-platform file paths
- **statistics** — Pure-Python mean/stdev for small samples

---

## 1. TradeRecord — Single Trade Data Structure

```python
from datetime import datetime
from xtrading.skills.trade_journal import TradeRecord

trade = TradeRecord(
    trade_id="T001",
    symbol="EURUSD",
    direction="long",
    entry_price=1.1000,
    exit_price=1.1050,
    quantity=1.0,              # lots
    entry_time=datetime(2025, 3, 10, 9, 0),
    exit_time=datetime(2025, 3, 10, 11, 30),
    stop_loss=1.0970,
    take_profit=1.1060,
    gross_pnl=500.0,
    commission=3.5,
    swap=0.0,
    risk_amount=300.0,
    r_multiple=1.65,           # net_pnl / risk_amount
    setup_tag="OB_pullback",
    session_tag="London",
    timeframe="H1",
    market_condition="trending",
    notes="Clean OB retest, strong momentum",
)

# Auto-computed fields:
# trade.net_pnl         → 496.5  (gross - commission - swap)
# trade.outcome         → "win"  (net_pnl > 0)
# trade.duration_minutes → 150
# trade.day_of_week     → "Mon"
# trade.hour_of_day     → 9
```

### TradeRecord Fields Reference

| Field | Type | Description |
|-------|------|-------------|
| `trade_id` | `str` | Unique identifier (required) |
| `symbol` | `str` | Instrument (e.g. "EURUSD") |
| `direction` | `"long"\|"short"` | Trade direction |
| `entry_price` | `float` | Entry fill price |
| `exit_price` | `float` | Exit fill price |
| `quantity` | `float` | Lots / shares / contracts |
| `gross_pnl` | `float` | P&L before costs |
| `commission` | `float` | Total broker commission |
| `swap` | `float` | Overnight swap/rollover cost |
| `net_pnl` | `float` | Auto-computed if left 0.0 |
| `risk_amount` | `float` | Dollar risk per trade |
| `r_multiple` | `float` | `net_pnl / risk_amount` |
| `mae` | `float` | Max Adverse Excursion (price) |
| `mfe` | `float` | Max Favorable Excursion (price) |
| `setup_tag` | `str` | Setup label (e.g. "FVG_fill") |
| `session_tag` | `str` | Session (e.g. "London") |
| `outcome` | `"win"\|"loss"\|"breakeven"\|"open"` | Auto-detected from net_pnl |

---

## 2. TradeJournal — CRUD and Persistence

```python
from xtrading.skills.trade_journal import TradeJournal

# Create journal (optional JSON persistence)
journal = TradeJournal(
    journal_path="my_journal.json",
    account_name="Prop Account",
    initial_balance=50_000.0,
)

# Add trades
journal.add_trade(trade)          # returns trade_id

# Update a field
journal.update_trade("T001", notes="Updated note", r_multiple=1.70)

# Retrieve
t = journal.get_trade("T001")

# Delete
journal.delete_trade("T001")     # returns True if found

# Querying with filters
trades = journal.get_trades(
    symbol="EURUSD",
    setup_tag="OB_pullback",
    session_tag="London",
    from_date=date(2025, 1, 1),
    to_date=date(2025, 3, 31),
    direction="long",
    outcome="win",
    min_r=1.0,                    # only trades with R ≥ 1.0
)

# Convert to DataFrame for custom analysis
df = journal.to_dataframe()

# Export to CSV
journal.export_csv("journal_export.csv")

# Persistence is automatic — every add/update/delete saves to JSON
len(journal)   # → 42 trades
repr(journal)  # → "TradeJournal(account='Prop Account', trades=42)"
```

### File Persistence Format
The JSON file structure allows portable sharing between machines:
```json
{
  "account": "Prop Account",
  "initial_balance": 50000.0,
  "trades": [
    {
      "trade_id": "T001",
      "entry_time": "2025-03-10T09:00:00",
      "exit_time": "2025-03-10T11:30:00",
      ...
    }
  ]
}
```

---

## 3. PerformanceAnalytics — Trading Statistics

```python
from xtrading.skills.trade_journal import PerformanceAnalytics

analytics = PerformanceAnalytics(journal.get_trades())

# Individual metrics
wr     = analytics.win_rate()          # 0.623  (62.3%)
exp    = analytics.expectancy()        # +0.42R per trade
pf     = analytics.profit_factor()    # 2.15
sharpe = analytics.sharpe_ratio()     # 1.34 (annualised)
sortino = analytics.sortino_ratio()   # 1.89 (downside only)
sqn    = analytics.sqn()             # 2.87 (> 2 = good)
dur    = analytics.avg_trade_duration()  # 142.5 minutes

# Full report (all metrics in one call)
report = analytics.full_report()
# {
#   "n_trades": 50,   "n_wins": 31,   "n_losses": 18,
#   "win_rate": 0.62, "win_rate_pct": 62.0,
#   "expectancy_r": 0.42,
#   "profit_factor": 2.15,
#   "avg_win_r": 1.85,   "avg_loss_r": 1.12,
#   "best_trade_r": 4.20, "worst_trade_r": -2.10,
#   "total_net_pnl": 8420.0,
#   "sharpe_ratio": 1.34,  "sortino_ratio": 1.89,
#   "sqn": 2.87,
#   "max_drawdown_pct": 8.2,
#   "calmar_ratio": 5.1,
#   "avg_duration_min": 142.5,
#   "total_commission": 175.0,
# }
```

### Metric Interpretation Guide

| Metric | Poor | Acceptable | Good | Excellent |
|--------|------|------------|------|-----------|
| Win Rate | < 35% | 35–45% | 45–65% | > 65% |
| Expectancy | < 0 | 0–0.2R | 0.2–0.5R | > 0.5R |
| Profit Factor | < 1.0 | 1.0–1.5 | 1.5–2.0 | > 2.0 |
| SQN | < 1.6 | 1.6–2.0 | 2.0–3.0 | > 3.0 |
| Sharpe | < 0.5 | 0.5–1.0 | 1.0–2.0 | > 2.0 |
| Max Drawdown | > 25% | 15–25% | 8–15% | < 8% |

### Key Formulas

```
Expectancy   = WR × Avg_Win_R − (1−WR) × Avg_Loss_R
Profit Factor = Gross_Profit / Gross_Loss
SQN          = (Expectancy / StdDev_R) × √(n_trades)
Sharpe       = (Daily_PnL_mean − rf/252) / Daily_PnL_std × √252
Sortino      = (Daily_PnL_mean − rf/252) / Downside_Std × √252
Calmar       = Annualised_Return / Max_Drawdown_pct
```

---

## 4. StreakAnalyser — Win/Loss Streak Detection

```python
from xtrading.skills.trade_journal import StreakAnalyser

streaks = StreakAnalyser(journal.get_trades())

# Current active streak
current = streaks.current_streak()
# {"streak": 4, "type": "win", "message": "4-trade WIN streak"}

# Maximum streaks in history
maxima = streaks.max_streaks()
# {
#   "max_win_streak": 8,
#   "max_loss_streak": 5,
#   "current": {"streak": 4, "type": "win", "message": "..."}
# }

# Distribution of streak lengths
dist = streaks.streak_distribution()
# {
#   "win_streaks":  {1: 12, 2: 8, 3: 4, 4: 2, 8: 1},
#   "loss_streaks": {1: 10, 2: 5, 3: 2, 5: 1},
#   "avg_win_streak": 1.9,
#   "avg_loss_streak": 1.7,
# }

# Revenge trading detection (performance after losing trades)
after_loss = streaks.after_loss_performance()
# {
#   "n_after_loss": 18,
#   "avg_r_after_loss": -0.15,
#   "revenge_trading_risk": True,   # True when avg < -0.3R
#   "trades_after_loss": [-1.2, 0.8, -0.9, ...]
# }
```

**Revenge Trading Alert**: `revenge_trading_risk=True` indicates the trader is
taking on poor quality trades after losses (avg R < −0.3 in the next trade).

---

## 5. DrawdownTracker — Equity Curve & Drawdown Analysis

```python
from xtrading.skills.trade_journal import DrawdownTracker

dd = DrawdownTracker(journal.get_trades(), initial_balance=50_000.0)

# Build equity curve (pd.Series indexed by datetime)
equity = dd.equity_curve()
# 2025-01-02    50000.0
# 2025-01-03    50450.0
# ...

# Full drawdown statistics
result = dd.calculate()
# {
#   "max_drawdown": 4200.0,             # in dollars
#   "max_drawdown_pct": 8.2,            # % from peak
#   "max_drawdown_duration_days": 12,   # days to recovery
#   "current_drawdown_pct": 1.5,        # current DD from peak
#   "peak_equity": 58400.0,
#   "current_equity": 57524.0,
#   "total_return_pct": 15.05,
# }

# Monthly P&L breakdown
monthly = dd.monthly_pnl()
#           net_pnl  n_trades  avg_pnl
# 2025-01   1842.00        18   102.33
# 2025-02   2315.00        22   105.23
# 2025-03    763.00        10    76.30
```

---

## 6. TagAnalytics — Drill-Down by Any Dimension

```python
from xtrading.skills.trade_journal import TagAnalytics

tag = TagAnalytics(journal.get_trades())

# Performance by any field
by_setup = tag.by_tag("setup_tag")
#    setup_tag     n_trades  win_rate  expectancy  profit_factor  avg_r  total_pnl
# 0  OB_pullback         18     0.722       0.845           3.12   1.25    4215.0
# 1  FVG_fill            12     0.583       0.320           1.85   0.72    2100.0
# 2  BOS_entry            8     0.500       0.125           1.42   0.55     800.0

by_session = tag.by_tag("session_tag")
by_symbol  = tag.by_tag("symbol")
by_dow     = tag.by_tag("day_of_week")
by_tf      = tag.by_tag("timeframe")
by_market  = tag.by_tag("market_condition")

# Top setups with at least N trades
top_setups = tag.best_setups(min_trades=5)

# Session performance as list of dicts
sessions = tag.session_breakdown()
# [{"session_tag": "London", "n_trades": 22, "win_rate": 0.68, ...},
#  {"session_tag": "NewYork", "n_trades": 18, "win_rate": 0.61, ...}]

# Heatmap: average R by hour and day of week
heatmap = tag.time_of_day_heatmap()
#        Mon   Tue   Wed   Thu   Fri
# hour
# 7     0.82  1.20  0.45  0.91  0.33
# 8     1.42  0.98  1.15  0.72  0.88
# 9     1.85  1.32  1.60  1.45  1.10
# 10    0.65  0.72  0.80  0.55  0.42
```

### Drillable Tag Fields

| Tag Field | Purpose |
|-----------|---------|
| `setup_tag` | ICT model, pattern type |
| `session_tag` | London / NewYork / Asian |
| `symbol` | Per-instrument performance |
| `timeframe` | H1 / H4 / D1 |
| `direction` | Long vs Short bias |
| `day_of_week` | Best trading days |
| `market_condition` | Trending vs Ranging |

---

## 7. JournalReporter — Report Generation

```python
from xtrading.skills.trade_journal import JournalReporter

reporter = JournalReporter(journal)

# Console text summary
print(reporter.text_summary())
# ============================================================
#   TRADING PERFORMANCE REPORT — Prop Account
# ============================================================
#   Trades     : 50 total  (31W / 18L)
#   Win Rate   : 62.0%
#   Expectancy : +0.42R per trade
#   Profit Fac : 2.15
#   Total P&L  : $8,420.00
#   Avg Win    : +1.85R  |  Avg Loss: 1.12R
#   Best Trade : +4.20R  |  Worst: -2.10R
#   SQN        : 2.87
#   Sharpe     : 1.34
#   Max DD     : 8.2%
#   Current DD : 1.5%
#   Max W Str  : 8 | Max L Str: 5
#   Current    : 4-trade WIN streak
# ============================================================

# Markdown report (for Obsidian, Notion, GitHub)
md = reporter.markdown_report()
# Includes: Summary stats table + Performance by Setup table

# Self-contained HTML report (dark theme, no dependencies)
html = reporter.html_report()
with open("report.html", "w") as f:
    f.write(html)

# Report on a subset of trades
london_trades = journal.get_trades(session_tag="London")
print(reporter.text_summary(london_trades))
```

---

## Full Workflow Example

```python
from datetime import datetime, date
from xtrading.skills.trade_journal import (
    TradeRecord, TradeJournal, PerformanceAnalytics,
    StreakAnalyser, DrawdownTracker, TagAnalytics, JournalReporter,
)

# 1. Create / load journal
journal = TradeJournal("journal.json", "My Prop Account", 100_000)

# 2. Log trades
for trade_data in my_trade_source:
    journal.add_trade(TradeRecord(**trade_data))

# 3. Analyse all trades
analytics = PerformanceAnalytics(journal.get_trades())
report = analytics.full_report()

# 4. Check for patterns
streaks = StreakAnalyser(journal.get_trades())
if streaks.after_loss_performance().get("revenge_trading_risk"):
    print("⚠️ Revenge trading detected — consider a break rule")

# 5. Drawdown check
dd = DrawdownTracker(journal.get_trades(), journal.initial_balance).calculate()
if dd["current_drawdown_pct"] > 10:
    print(f"⛔ Max daily loss approaching: {dd['current_drawdown_pct']:.1f}% DD")

# 6. Find your best setups
tag = TagAnalytics(journal.get_trades())
print(tag.best_setups(min_trades=5).to_string())

# 7. Generate reports
reporter = JournalReporter(journal)
print(reporter.text_summary())
html = reporter.html_report()
```

---

## Usage Conventions

1. **R-multiples** — always set `risk_amount` for meaningful `r_multiple` values
2. **outcome** — auto-detected from `net_pnl`; explicitly set `"open"` for live trades
3. **session_tag** — use consistent labels: `"London"`, `"NewYork"`, `"Asian"`, `"Overlap"`
4. **Sharpe/Sortino** — require ≥ 5 closed trades; meaningful only at ≥ 20
5. **SQN benchmark** — > 2.0 good, > 3.0 excellent, > 5.0 exceptional (Van Tharp)
6. **Persistence** — auto-saves on every CRUD operation when `journal_path` is set
7. **Filtering** — combine `get_trades()` filters then pass subset to any analyser class

---

## Related Skills

- [Risk Performance](../risk-and-portfolio.md)
- [Risk And Portfolio](../risk-and-portfolio.md)
- [Backtesting Sim](../backtesting-sim.md)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.