trading-journal

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: MIT

README

tj — a trading journal that tells you what your mistakes cost

A single-binary command-line trading journal. It records trades, checks them against rules you define, and answers one question a spreadsheet cannot:

in dollars, what has breaking your own rules cost you?

$ tj stats --by compliance
RULES        TRADES         P&L   WIN%  EXPECTANCY   AVG R  AVG HOLD
Followed          3  +$1,353.00  66.7%    +$451.00  +2.14R       31m         │██████
Broken            5  -$2,011.60   0.0%    -$402.32  -1.01R       18m  ███████│

Breaking the rules has cost $2,011.60 across 5 trade(s).
Per trade: +$451.00 clean, -$402.32 broken.

Built to replace a multi-sheet Excel tracker. Along the way it found four bugs in that spreadsheet, each of which had been quietly corrupting the numbers it was trusted for — see DECISIONS.md.


Install

go install github.com/henryikoh/trading-journal/cmd/tj@latest

Or build it:

git clone https://github.com/henryikoh/trading-journal
cd trading-journal
go build -o tj ./cmd/tj

No CGO, no runtime dependencies. CGO_ENABLED=0 go build gives a static binary you can copy to a server.

The journal lives in a single SQLite file at ~/.tj/journal.db. Nothing else is required. Point --db at a postgres:// URL if you would rather it lived on a server.


Quick start

tj account new --name "My Account" --balance 10000 --instrument XAUUSD
tj open      # asks for everything; no flags needed
tj close     # lists what is open, asks for the exit
tj stats     # what it all came to

The daily loop

tj today          # briefing: the session timeline, your allowance, open positions
tj open           # log a trade
tj close          # close one
tj note "..."     # the day's reflection

tj today opens with the trading day drawn as a bar in your own timezone, then your remaining trade allowance at a size you cannot skim past:

 6a       9a       12p      3p       6p       9p       12a      3a
 ····························································████████████
                                                          ▲
                                                       1:07 am

 ██ Asia 2:00 am-6:00 am   ░░ New York 2:00 pm-5:00 pm (Mon-Fri)

   ███ ███ ┃ ┃ ░░░   2 of 4 left
   win los next

Trades past the limit are drawn as ╳╳╳ and keep accumulating, because the point is to make overtrading visible while it is happening rather than in a review a week later.


What makes it different

It never guesses

Grade and emotional state are blank if you do not give them, not defaulted. Imported trades with no stop have no R multiple, not zero. A trade the rule engine has never examined is reported as unchecked, not as clean. Every figure on screen is either measured or absent.

The checklist is half derived

Four of the pre-trade checks are facts the journal already holds — whether a session is open, whether the trade limit is spent, whether the risk budget covers the trade, whether anything else is blocking. --checklist all cannot assert them. Only what a human can know is asked.

PRE-TRADE CHECK
  ✓ Inside the trading window    New York
  ✓ Within the trade limit       0 of 4 used
  ✗ Within the daily risk        $12.40 left of $250.00
  ✓ Status allows the trade      nothing else blocking
Rules are recorded, never enforced

A journal that refuses entries gets bypassed — the trade goes into the broker directly and the log goes blind. So it logs the trade and records the breach. The value is in --by compliance being able to price the habit later.

Your systems are yours

A playbook is one setup's checks, in the order you work through them:

tj playbook new "Range Fade" \
  --check "Price at the range boundary" \
  --check "Rejection wick into the level" \
  --check "Volume falling into the edge"

Each trade stores the questions it was actually asked, so editing a playbook never rewrites history. tj stats --by playbook then answers which of your systems makes money.


Commands

Trading
tj open log a trade — asks for everything, or takes flags
tj close [n] close a trade, or list what is open
tj preview size a trade without logging it
tj edit <n> revise the notes or grade
tj delete <n> remove a mistyped trade
Review
tj status balances, risk budget, whether you may trade
tj today the day briefing
tj portfolio every active account, with capital allocation
tj show <n> one trade in full, including its checklist at entry
tj log the trade log, filterable
tj week this week, a bar per day
tj stats [--by …] performance, broken down eleven ways
tj streak days in a row with every rule kept
tj export the trade log as CSV
Setup and money
tj account list | new | show | edit | use
tj account archive | close | reopen accounts holding trades are never deleted
tj playbook your systems and their checks
tj instruments what each contract is worth
tj deposit | withdraw funding and payouts, each removable if mistyped
tj import <file> load a broker statement or a spreadsheet
tj recheck judge trades the rule engine never saw
tj config journal path, timezone, 12- or 24-hour clock

tj help <command> explains any of them.

Breakdowns

tj stats --by <what>:

compliance what following the rules earns against what breaking them costs
duration hold time — where the disposition effect shows up
day each trading day against your daily trade limit
index 1st, 2nd, 3rd trade of the day, banded past the limit
checklist which pre-trade item is expensive to skip
playbook which of your systems actually makes money
session · grade · emotional · hour · account

Importing

tj import statement.html -a my-account --tz America/New_York --dry-run

Reads CSV, TSV, and the HTML reports MT4/MT5 produce (including UTF-16). It also reads a hand-kept spreadsheet: headings are normalised before matching, so P&L $, Profit (USD) and pnl are one column, and values keep their meaning with the currency symbols stripped.

  • The broker's profit is authoritative — it already includes spread, commission and swap, which prices alone cannot reproduce.
  • Direction is taken in order of trustworthiness: the broker's side column, then the exit price against the realised profit, then the stop. That middle rule matters — a hand-kept sheet gets the stop backwards more often than you would think, and every disagreement is reported.
  • Rows are keyed on the broker's ticket, or a stable id derived from the trade when there is none, so re-importing a corrected file updates rather than duplicates.
  • Imported trades are put through the rule engine afterwards, because a trade nobody examined is not a clean one.

--tz matters: statement timestamps carry no timezone, and reading them in the wrong one files every trade under the wrong session.


Two clocks, and a trading day that is not a date

Session windows belong to the market (America/New_York). Every time on screen is rendered in yours. They are separate because you are probably not in New York.

The trading day is not the calendar date either. It opens with New York and closes when the Asia session that started the previous evening ends — so a fill at 00:20 belongs to the day that began the morning before. Read from Lagos, the day rolls over at 6:00 am local, and shifts to 7:00 am when New York leaves daylight saving, because the sessions are anchored to the market rather than to a wall clock.


Architecture

cmd/tj/            the CLI
internal/
  domain/          types: Account, Trade, Instrument, Checklist, Playbook
  calc/            the maths — pure, no I/O, no clock
  risk/            budgets, gating status, violation detection
  prop/            drawdown, consistency ceiling, payout eligibility
  store/           SQLite and PostgreSQL from one set of queries
  journal/         service layer: loads state, calls the engines, builds views
  tui/             terminal rendering
  config/          journal path, active account, display preferences

calc, risk and prop are pure functions over data the service layer supplies. Nothing in them opens a database or reads a clock, which is why they can be tested against real historical fills with known broker-reported P&L.

All derived values are produced in journal, so the CLI and any future HTTP API cannot disagree about a number.

Dependencies, four, deliberately:

modernc.org/sqlite     pure-Go SQLite — CGO_ENABLED=0 gives a static binary
github.com/lib/pq      PostgreSQL
github.com/google/uuid
golang.org/x/term      raw mode for the arrow-key pickers

Testing

go test ./...

105 test functions. The calculation tests use real historical fills with known broker-reported P&L, so a regression fails against reality rather than against an assumption.


Status

Working and in daily use: accounts, the calculation engine, risk and prop rules, playbooks, storage, the CLI, and importing.

Not built: an HTTP API and web dashboard. The service layer already returns the structs an API would serialise, so what is missing is transport and auth.

Open questions are listed at the end of DECISIONS.md, including one about the daily risk formula that is still under review.


A word of caution

This tool measures your trading. It does not improve it, predict anything, or know whether a setup is good.

Nothing here is financial advice. It ships with no warranty of any kind — see the licence. If a number matters to you, check it against your broker statement. A journal is only ever as honest as what you put into it.


Licence

MIT.

Directories

Path Synopsis
cmd
tj command
Command tj is the trading journal CLI.
Command tj is the trading journal CLI.
internal
calc
Package calc holds the pure calculation engine: no I/O, no database, no clock beyond what callers pass in.
Package calc holds the pure calculation engine: no I/O, no database, no clock beyond what callers pass in.
config
Package config resolves where the journal lives and which account is active.
Package config resolves where the journal lives and which account is active.
domain
Package domain holds the core types of the journal.
Package domain holds the core types of the journal.
journal
Package journal is the service layer.
Package journal is the service layer.
prop
Package prop implements prop-firm rulebooks: drawdown floors, consistency ceilings, challenge progress and payout eligibility.
Package prop implements prop-firm rulebooks: drawdown floors, consistency ceilings, challenge progress and payout eligibility.
risk
Package risk turns an account's balance and the day's activity into the numbers that gate trading: risk per trade, the daily budget, and whether a trade is allowed right now.
Package risk turns an account's balance and the day's activity into the numbers that gate trading: risk per trade, the daily budget, and whether a trade is allowed right now.
store
Package store persists the journal.
Package store persists the journal.
tui
Package tui renders the CLI output: boxes, tables, and the small charts that make a terminal session readable at a glance.
Package tui renders the CLI output: boxes, tables, and the small charts that make a terminal session readable at a glance.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL