Good Python commenting practices are not optional polish; they are how you signal assumptions and protect your code from breaking when someone else reads or uses it. This post shows you when to comment, what to say, and how to build the habit so your code is safe to hand over and clear enough to audit.
Why comments matter in finance work
You are writing code to calculate a liquidity coverage ratio or to populate a regulatory return. Six months from now, you will need to change it. Or a colleague will. Or an auditor will want to understand what you did and why.
Code without comments is a tax on everyone who reads it later. In finance, that tax is high. A misread assumption about a date convention or a rate input can push a number through a regulatory submission wrong. A week later you are back in a spreadsheet trying to find it.
Comments are not optional polish. They are a core skill. Comments are how you tell the story of what your code does and, more importantly, why you made the decisions you made.
The goal of this post is to show you when to comment, what to say, and how to build the habit so your code is safe to hand over and clear enough to audit.
Single line comments: explain the why, not the what
The simplest comment in Python is a single line. It starts with a hash symbol and runs to the end of the line.
# This is a comment
print("This will run") # And this is a comment too
The compiler ignores everything after the hash. But your team reads it.
Here is where a lot of people go wrong. They comment what the code does:
# Add 2 to x
x = x + 2
The code already says that. Anyone who can read Python knows what x = x + 2 does. That comment adds nothing. Worse, if the code changes and the comment does not, they are now contradictory. A comment that lies is worse than no comment.
Instead, comment the why. Why are you adding 2? What does it mean in the context of your work?
# Add 2 basis points to convert from run rate to quoted rate (market convention)
x = x + 2
Now the comment tells you something the code does not. It tells you this is deliberate, it follows a market convention, and someone checking your work knows what assumption is baked in.
Here is another example from real finance work:
# Skip weekends: Monday is 0, Sunday is 6
if date.weekday() < 5:
process_trade(date)
Without the comment, someone reading this might think you are filtering for specific days of the week. With the comment, they understand the logic depends on Python's weekday convention and they know what "less than 5" means.
In finance work, these kinds of conventions matter. A single line comment capturing the assumption is not filler. It is a guard rail.
Comment the assumption or the decision, not the syntax. If you can read the operation from the code itself, your comment should explain why you chose it.
Multiline comments and docstrings for complex logic
When you have a larger block of logic or a function that does something non obvious, a multiline comment or a docstring is the right tool.
A multiline comment uses multiple hash symbols:
# Calculate the weighted average cost of funds
# This applies the 90 day historical volatility to each maturity bucket
# Excluded: balances maturing in under 3 months (no FTP charge)
weighted_cost = calculate_cost(volatility, buckets)
A docstring is a special string that sits right after a function or class definition:
def calculate_lcr(cash_inflows, cash_outflows, hqla):
"""
Calculate the Liquidity Coverage Ratio.
Assumes inflows and outflows are in the same currency.
HQLA includes Level 1 and Level 2a assets only (no haircuts applied here).
Returns the ratio as a decimal (0.5 means 50%).
"""
lcr = hqla / (cash_outflows - cash_inflows)
return lcr
The docstring serves two purposes. First, it documents the function so anyone reading the code knows what it does and what assumptions it makes. Second, if someone calls help(calculate_lcr) in Python, they will see it. This is not wasted effort.
Notice what the docstring captures: what the function does, what assumptions it depends on (same currency, which assets are included), and what the output looks like. That is exactly the information your auditor or your colleague needs.
Docstrings are the standard in professional Python. Use them for all functions that do substantive work. Use them for classes and complex modules too.
What to comment and what to leave alone
This is a judgement call, and practised teams develop their own norms. But here is a good principle: comment the hard parts and the risky parts. Leave the obvious ones alone.
A weekly note on treasury, liquidity and practical Python. No spam, unsubscribe any time.
Hard parts include:
- Business logic that depends on regulatory definitions or market conventions
- Calculations where the order of operations or the input assumptions matter
- Workarounds or edge cases you had to handle
- Decisions about which library or approach you chose and why
Obvious parts you can skip:
- Variable assignment:
balance = 0needs no comment; the variable name is self explanatory - Simple loops over a list:
for trade in trades:is self explanatory - Standard library calls that are common in your codebase
- Helper functions that are only used once and do exactly what their name says
# Example: what to comment and what to leave alone
balance = 0
# Calculate net cash flow over the LCR observation window
# Observation window is 30 calendar days per Basel III definition
# Outflows include deposits with no fixed maturity date at run off rate assumptions
net_flow = sum_inflows(30) - sum_outflows(30, run_off_rates)
for trade in trades:
if is_overdue(trade):
mark_for_escalation(trade)
# Data gap on test date due to system downtime; interpolate from nearest day
daily_spreads[test_date] = interpolate_spreads(test_date - 1, test_date + 1)
The comments in this example are there because they explain the why or capture a hidden assumption. The lines without comments speak for themselves.
Understanding date conventions with a concrete example
Finance code lives or dies on its assumptions. One of the most common sources of invisible error is the date convention. A comment is your chance to surface it.
Date convention means: how is the date represented? Is 2024 01 15 stored as a string like "2024-01-15", a datetime object, or as a number of days since 1900? Different systems use different conventions, and mixing them causes silent errors.
Here is what this looks like in practice:
def calculate_accrued_interest(balance, annual_rate, days_held):
"""
Calculate accrued interest.
Annual rate is a decimal (0.05 means 5%).
Days held is counted as actual calendar days (actual/360 convention).
Uses 360 day year (standard in money markets).
"""
daily_rate = annual_rate / 360
accrued = balance * daily_rate * days_held
return accrued
When you document the date convention (actual/360, not 365/365), you make it possible for someone else to spot when they have used a different system. Without this comment, the error is invisible until month end.
Comments as a hedge against assumptions
Every piece of finance logic rests on something: a date convention, a rate curve, a market spread, a definition from a regulation. These are invisible until they go wrong.
Here is what this looks like:
def calculate_ftp_charge(balance, tenor):
"""
Calculate funds transfer pricing charge.
Uses the firm's FTP curve effective from 2024 01 15.
Tenor is in days. Assumes 360 day year (money market convention).
Does not apply to repo or securities financing transactions.
"""
curve = load_ftp_curve("corporate", date(2024, 1, 15))
annual_rate = curve.interpolate(tenor / 360)
daily_charge = balance * annual_rate / 360
return daily_charge
Three months from now, someone runs this on a new dataset and wonders why the numbers are different. The comment tells them: check if you are using the right curve, check the date convention. It does not solve the problem, but it makes the problem visible instead of hidden.
This is especially critical when you hand code over. Your successor will not know what you knew. The comment is your communication with them.
In finance work, comments that flag assumptions are a key part of preventing regulatory reporting errors. They work alongside code review, testing, and controls to reduce risk.
The cost of unclear code in practice
The brief asked you to see this as a practitioner talking to another. So here is a real scenario.
You write a pricing model. The code works. You move on to other work.
Six months later, a trade support analyst runs it on a new trade and the output does not look right. They ask you what the code does. You no longer remember. You have to read it cold, line by line, to figure out what you were thinking. This takes two hours.
If the code had been well commented, the analyst could have spotted the assumption they broke (perhaps a date format, or an input shape) in ten minutes. They read the comment, spot the mismatch, and fix it themselves.
Now multiply this across a team. Multiply it across a year. Unclear code is not a minor inconvenience. It compounds.
In regulatory work, unclear code is even more serious. You prepare a return. An auditor asks you to explain the calculations. You generate a printout of the code. If there are no comments, you have to spend time explaining what the code does. If there are clear comments, you point to them and move on. Under time pressure at month end, this matters.
Clear code with good comments is faster to handover, easier to review, and less likely to be silently wrong.
Building the habit of clear commenting
This does not happen by accident. You have to build it into your routine.
Start with functions. Every function you write that does real work gets a docstring. Not sometimes. Every time. It takes thirty seconds and it saves hours later.
def run_off_rate_for_tenor(tenor_days, customer_segment):
"""
Retrieve the run off assumption for a given tenor and customer segment.
Run off rates reflect historical decay rates for deposits with no fixed maturity date.
Data is sourced from the ALM run off table, last refreshed 2024 01 10.
Tenor is in days. Returns decimal (0.05 means 5% per day).
Raises ValueError if tenor or segment not found in table.
"""
# Implementation here
Next, comment the tricky line. If you had to pause to write it, it probably needs a comment.
# Adjust for day count convention: actual/360 for money market products
annual_rate = (spread + curve_rate) * actual_days / 360
Third, flag the assumptions. Before you deploy code, read through it and ask: what could someone misunderstand? What breaks if the input is different?
Finally, review your own comments. Bad comments are worse than none. If your comment is just a restatement of the code, delete it. If it is out of date, update it or remove it. Stale comments are lies.
The practical takeaway
Comments are part of your responsibility as a professional. They are not optional and they are not for the compiler. They are for your team and your future self.
In finance work, that responsibility is higher. A misread assumption in commented code causes a weekend of rework. A misread assumption in uncommented code causes a regulatory query.
Write a docstring for every substantial function. Comment the decision, not the syntax. Flag the assumption. And build the habit now, when the code is new, so you do not have to retrofit it later when you have moved on.
If you are following the Python bootcamp series, you now have the tools to write readable, safe code. The next step is to use them, every time. Your team will thank you.
Start with the fundamentals if you have not already covered them: read code like you read English. See the full course roadmap to plan what comes next. And if you are new to Python in a finance context, get your environment set up properly so your code is version controlled and auditable from the start.
Get the next one in your inbox
A weekly note across Finance & Treasury, Innovation & Automation and Career Development. No spam, unsubscribe any time.
Practitioner notes on treasury, liquidity, regulatory reporting and practical Python.
