Excel VBA for Traders: Automating Spreadsheets That Actually Work¶
There is a joke on Wall Street that goes like this: “What technology powers the global financial system?” The intern says “Bloomberg Terminal.” The developer says “Python.” The quant says “C++.” And the person who actually keeps the lights on says “a 47-tab Excel spreadsheet that nobody understands and everyone is terrified to touch.”
That joke is barely a joke. Excel runs finance. It runs risk reports, P&L calculations, trade blotters, curve interpolation, position monitoring, and approximately 97% of all things that banks promise are “fully automated.” And the engine under the hood of these mission-critical spreadsheets? VBA. Visual Basic for Applications. The language that every developer loves to hate and every trader quietly depends on.
VBA is not glamorous. It will never trend on Hacker News. Nobody is writing Medium articles about “Why VBA is the Future.” But if you want to be useful in a finance environment, knowing how to write VBA that does not break at 6 AM when the London desk opens is worth its weight in gold.
Python may be the future, but VBA is the present. And the present pays the bills.
Why VBA Still Matters in Finance¶
Before we write a single line of code, let us address the elephant in the room. “Why not just use Python?”
Fair question. Here is why VBA still dominates:
Excel is already everywhere. Every desk, every bank, every fund has Excel. No installation required. No IT approval process. No virtual environment headaches. It is just there.
Traders live in Excel. They do not want a terminal. They do not want a web app. They want their spreadsheet. The one they have been using for 7 years. The one with the macros their predecessor wrote. Traders want their data where they can see it, touch it, and argue with it.
Speed of deployment. You can write a VBA macro, test it, and hand it to a trader in 20 minutes. Try deploying a Python application to a locked-down bank desktop in 20 minutes. Good luck.
Integration with everything. Bloomberg, Reuters, internal databases, emails, PowerPoint reports, you name it. VBA can talk to all of them through COM objects and add-ins.
Key Insight: VBA is not a good language for building scalable software systems. But it is an excellent language for solving “I need this specific thing automated in the tool I already use” problems. And finance is full of those problems.
The best code is the code that actually gets used. A perfect Python script sitting in a repo nobody looks at is worth less than a janky VBA macro that a trader runs 40 times a day.
VBA Fundamentals: The 20-Minute Crash Course¶
If you have never opened the VBA editor, here is the express version.
Opening the VBA Editor¶
Press Alt + F11 in Excel. That is it. You are now in the Visual Basic Editor (VBE). If that shortcut does not work, go to File > Options > Customize Ribbon and check “Developer” tab, then click “Visual Basic” from that tab.
Your First Macro¶
In the VBE, go to Insert > Module. Type the following:
Sub HelloTrader()
MsgBox "Good morning. Your P&L is still loading."
End Sub
Press F5 to run it. Congratulations, you have written your first VBA macro.
Variables and Data Types¶
VBA is statically typed (if you want it to be). Always declare your variables with Dim, and always use Option Explicit at the top of every module to force declaration.
Option Explicit
Sub VariableDemo()
Dim stockPrice As Double
Dim ticker As String
Dim quantity As Long
Dim isActive As Boolean
stockPrice = 142.57
ticker = "AAPL"
quantity = 1000
isActive = True
MsgBox ticker & " | Qty: " & quantity & " | Price: $" & stockPrice
End Sub
Not using Option Explicit is like driving without a seatbelt. You will feel fine until the day you misspell stockPirce and spend 3 hours wondering why your P&L is zero.
Key Data Types¶
| Type | Description | Example |
|---|---|---|
Integer | Whole numbers (-32,768 to 32,767) | Dim count As Integer |
Long | Larger whole numbers (+/- 2 billion) | Dim rowNum As Long |
Double | Floating-point numbers (15 digits) | Dim price As Double |
String | Text | Dim name As String |
Boolean | True/False | Dim isValid As Boolean |
Date | Date and time | Dim tradeDate As Date |
Variant | Can hold any type (avoid when possible) | Dim anything As Variant |
Key Insight: Always use
Longinstead ofIntegerfor row counters and loop variables. Excel has over 1 million rows, andIntegermaxes out at 32,767. This is one of the most common VBA bugs in finance, and it will only show up when you process a large dataset, which is exactly when you cannot afford bugs.
Reading and Writing Cells¶
This is the bread and butter. Everything in VBA finance boils down to reading numbers from cells, doing something with them, and writing results back.
Sub CellBasics()
' Reading a cell value
Dim price As Double
price = Range("B2").Value
' Writing to a cell
Range("C2").Value = price * 1.1 ' 10% markup
' Using Cells(row, column) notation
Dim i As Long
For i = 2 To 10
Cells(i, 4).Value = Cells(i, 2).Value * Cells(i, 3).Value
Next i
' Referencing a specific sheet
Worksheets("Trades").Range("A1").Value = "Trade ID"
End Sub
Loops and Conditionals¶
Sub LoopExample()
Dim i As Long
Dim lastRow As Long
' Find the last row with data in column A
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
If Cells(i, 3).Value > 100 Then
Cells(i, 4).Value = "Large Trade"
ElseIf Cells(i, 3).Value > 10 Then
Cells(i, 4).Value = "Medium Trade"
Else
Cells(i, 4).Value = "Small Trade"
End If
Next i
End Sub
Finding the last row with Cells(Rows.Count, 1).End(xlUp).Row is the VBA equivalent of a secret handshake. If you know this line by heart, people will trust you with their spreadsheets.
Project 1: Bond Price Calculator¶
Let us build something real. A bond pricer that calculates the present value of a fixed-rate bond given its coupon rate, face value, yield to maturity, and number of periods.
The Math¶
The price of a bond is the sum of the present values of all future cash flows:
Bond Price = sum(C / (1 + y)^t, t=1..n) + F / (1 + y)^n
Where:
- C = coupon payment per period
- y = yield to maturity per period
- F = face value (par value)
- n = number of periods
The Spreadsheet Layout¶
| Row | A | B |
|---|---|---|
| 1 | Parameter | Value |
| 2 | Face Value | 1000 |
| 3 | Coupon Rate (annual) | 5.00% |
| 4 | Yield to Maturity (annual) | 4.00% |
| 5 | Years to Maturity | 10 |
| 6 | Payments per Year | 2 |
| 7 | Bond Price | (calculated) |
| 8 | Accrued Interest | (calculated) |
The VBA Code¶
Option Explicit
Sub CalculateBondPrice()
Dim faceValue As Double
Dim couponRate As Double
Dim ytm As Double
Dim years As Long
Dim frequency As Long
Dim couponPayment As Double
Dim periodicYield As Double
Dim nPeriods As Long
Dim bondPrice As Double
Dim pvCoupons As Double
Dim pvFace As Double
Dim t As Long
' Read inputs from the spreadsheet
faceValue = Range("B2").Value
couponRate = Range("B3").Value
ytm = Range("B4").Value
years = Range("B5").Value
frequency = Range("B6").Value
' Calculate derived values
couponPayment = (couponRate * faceValue) / frequency
periodicYield = ytm / frequency
nPeriods = years * frequency
' Calculate present value of coupon payments
pvCoupons = 0
For t = 1 To nPeriods
pvCoupons = pvCoupons + couponPayment / (1 + periodicYield) ^ t
Next t
' Calculate present value of face value
pvFace = faceValue / (1 + periodicYield) ^ nPeriods
' Total bond price
bondPrice = pvCoupons + pvFace
' Write result
Range("B7").Value = bondPrice
Range("B7").NumberFormat = "$#,##0.00"
' Display summary
MsgBox "Bond Price: $" & Format(bondPrice, "#,##0.00") & vbCrLf & _
"Coupon per period: $" & Format(couponPayment, "#,##0.00") & vbCrLf & _
"Number of periods: " & nPeriods & vbCrLf & _
"Premium/Discount: $" & Format(bondPrice - faceValue, "#,##0.00")
End Sub
Running the Example¶
With the inputs above (5% coupon, 4% yield, 10 years, semi-annual):
- Coupon payment per period: $25.00
- Number of periods: 20
- PV of coupons: $410.24
- PV of face value: $672.97
- Bond price: $1,082.21
The bond trades at a premium ($1,082.21 > $1,000) because the coupon rate (5%) exceeds the yield (4%). Investors are willing to pay more for higher-than-market coupons.
| Yield | Bond Price | Premium/Discount |
|---|---|---|
| 3.00% | $1,170.30 | +$170.30 (Premium) |
| 4.00% | $1,082.21 | +$82.21 (Premium) |
| 5.00% | $1,000.00 | $0.00 (Par) |
| 6.00% | $925.61 | -$74.39 (Discount) |
| 7.00% | $858.10 | -$141.90 (Discount) |
Key Insight: When the coupon rate equals the yield to maturity, the bond trades at exactly par ($1,000). This is not a coincidence, it is a mathematical identity. The bond is paying exactly what the market demands, so nobody needs to pay a premium or accept a discount.
If your bond pricer returns $1,000 when the coupon equals the yield, your code is correct. If it does not, go back and check your loop bounds.
Project 2: Automated P&L Report¶
Every morning, traders want to know one thing: “How much did I make or lose?” Let us automate that.
The Setup¶
Assume you have a “Trades” sheet with this structure:
| A | B | C | D | E |
|---|---|---|---|---|
| Trade ID | Ticker | Quantity | Entry Price | Current Price |
| T001 | AAPL | 500 | 142.50 | 148.20 |
| T002 | MSFT | -200 | 380.00 | 375.50 |
| T003 | GOOGL | 100 | 140.25 | 152.80 |
| T004 | TSLA | -150 | 245.00 | 258.30 |
Negative quantity means a short position.
The VBA Code¶
Option Explicit
Sub GeneratePnLReport()
Dim wsTrades As Worksheet
Dim wsReport As Worksheet
Dim lastRow As Long
Dim i As Long
Dim reportRow As Long
Dim quantity As Long
Dim entryPrice As Double
Dim currentPrice As Double
Dim pnl As Double
Dim totalPnL As Double
Dim totalLongs As Double
Dim totalShorts As Double
Set wsTrades = Worksheets("Trades")
' Create or clear the Report sheet
On Error Resume Next
Set wsReport = Worksheets("P&L Report")
On Error GoTo 0
If wsReport Is Nothing Then
Set wsReport = Worksheets.Add(After:=Worksheets(Worksheets.Count))
wsReport.Name = "P&L Report"
Else
wsReport.Cells.Clear
End If
' Write headers
With wsReport
.Range("A1").Value = "P&L Report - " & Format(Now, "dd-mmm-yyyy hh:mm")
.Range("A1").Font.Bold = True
.Range("A1").Font.Size = 14
.Range("A3").Value = "Trade ID"
.Range("B3").Value = "Ticker"
.Range("C3").Value = "Position"
.Range("D3").Value = "Quantity"
.Range("E3").Value = "Entry Price"
.Range("F3").Value = "Current Price"
.Range("G3").Value = "P&L ($)"
.Range("H3").Value = "P&L (%)"
.Range("A3:H3").Font.Bold = True
.Range("A3:H3").Interior.Color = RGB(51, 51, 51)
.Range("A3:H3").Font.Color = RGB(255, 255, 255)
End With
lastRow = wsTrades.Cells(wsTrades.Rows.Count, 1).End(xlUp).Row
reportRow = 4
totalPnL = 0
totalLongs = 0
totalShorts = 0
For i = 2 To lastRow
quantity = wsTrades.Cells(i, 3).Value
entryPrice = wsTrades.Cells(i, 4).Value
currentPrice = wsTrades.Cells(i, 5).Value
' P&L calculation (works for both long and short positions)
pnl = quantity * (currentPrice - entryPrice)
totalPnL = totalPnL + pnl
' Track long/short exposure
If quantity > 0 Then
totalLongs = totalLongs + quantity * currentPrice
Else
totalShorts = totalShorts + Abs(quantity) * currentPrice
End If
' Write to report
With wsReport
.Cells(reportRow, 1).Value = wsTrades.Cells(i, 1).Value
.Cells(reportRow, 2).Value = wsTrades.Cells(i, 2).Value
.Cells(reportRow, 3).Value = IIf(quantity > 0, "LONG", "SHORT")
.Cells(reportRow, 4).Value = Abs(quantity)
.Cells(reportRow, 5).Value = entryPrice
.Cells(reportRow, 6).Value = currentPrice
.Cells(reportRow, 7).Value = pnl
.Cells(reportRow, 8).Value = pnl / (Abs(quantity) * entryPrice)
' Color P&L cells
If pnl > 0 Then
.Cells(reportRow, 7).Font.Color = RGB(0, 128, 0)
ElseIf pnl < 0 Then
.Cells(reportRow, 7).Font.Color = RGB(200, 0, 0)
End If
End With
reportRow = reportRow + 1
Next i
' Format number columns
With wsReport
.Range("E4:F" & reportRow - 1).NumberFormat = "$#,##0.00"
.Range("G4:G" & reportRow - 1).NumberFormat = "$#,##0.00"
.Range("H4:H" & reportRow - 1).NumberFormat = "0.00%"
' Summary section
.Cells(reportRow + 1, 1).Value = "TOTAL P&L:"
.Cells(reportRow + 1, 1).Font.Bold = True
.Cells(reportRow + 1, 7).Value = totalPnL
.Cells(reportRow + 1, 7).Font.Bold = True
.Cells(reportRow + 1, 7).NumberFormat = "$#,##0.00"
.Cells(reportRow + 2, 1).Value = "Long Exposure:"
.Cells(reportRow + 2, 7).Value = totalLongs
.Cells(reportRow + 2, 7).NumberFormat = "$#,##0.00"
.Cells(reportRow + 3, 1).Value = "Short Exposure:"
.Cells(reportRow + 3, 7).Value = totalShorts
.Cells(reportRow + 3, 7).NumberFormat = "$#,##0.00"
.Cells(reportRow + 4, 1).Value = "Net Exposure:"
.Cells(reportRow + 4, 7).Value = totalLongs - totalShorts
.Cells(reportRow + 4, 7).NumberFormat = "$#,##0.00"
' Auto-fit columns
.Columns("A:H").AutoFit
End With
MsgBox "P&L Report generated!" & vbCrLf & _
"Total P&L: " & Format(totalPnL, "$#,##0.00"), _
vbInformation, "Report Complete"
End Sub
Output for Our Example¶
| Trade ID | Ticker | Position | Qty | Entry | Current | P&L ($) | P&L (%) |
|---|---|---|---|---|---|---|---|
| T001 | AAPL | LONG | 500 | $142.50 | $148.20 | $2,850.00 | 4.00% |
| T002 | MSFT | SHORT | 200 | $380.00 | $375.50 | $900.00 | 1.18% |
| T003 | GOOGL | LONG | 100 | $140.25 | $152.80 | $1,255.00 | 8.95% |
| T004 | TSLA | SHORT | 150 | $245.00 | $258.30 | -$1,995.00 | -5.43% |
Total P&L: $3,010.00
The AAPL and GOOGL longs are making money. The MSFT short is winning too (price went down, which is what you want when you are short). But that TSLA short is hurting. Elon probably tweeted something.
Project 3: Yield Curve Interpolation¶
You have a handful of benchmark yields (1Y, 2Y, 5Y, 10Y, 30Y) and you need to estimate the yield for maturities in between. This is linear interpolation on the yield curve, something every fixed income desk does daily.
The VBA Code¶
Option Explicit
Function InterpolateYield(targetMaturity As Double, _
maturities As Range, _
yields As Range) As Double
'
' Linearly interpolates a yield for a given maturity
' from a set of benchmark maturities and yields.
'
Dim n As Long
Dim i As Long
Dim x1 As Double, x2 As Double
Dim y1 As Double, y2 As Double
n = maturities.Cells.Count
' Handle edge cases: target outside the curve
If targetMaturity <= maturities.Cells(1).Value Then
InterpolateYield = yields.Cells(1).Value
Exit Function
End If
If targetMaturity >= maturities.Cells(n).Value Then
InterpolateYield = yields.Cells(n).Value
Exit Function
End If
' Find the two surrounding points
For i = 1 To n - 1
If maturities.Cells(i).Value <= targetMaturity And _
targetMaturity <= maturities.Cells(i + 1).Value Then
x1 = maturities.Cells(i).Value
x2 = maturities.Cells(i + 1).Value
y1 = yields.Cells(i).Value
y2 = yields.Cells(i + 1).Value
' Linear interpolation formula
InterpolateYield = y1 + (y2 - y1) * _
(targetMaturity - x1) / (x2 - x1)
Exit Function
End If
Next i
End Function
Usage in a Spreadsheet¶
Set up your benchmark data:
| A | B |
|---|---|
| Maturity (Years) | Yield (%) |
| 0.25 | 4.85 |
| 0.5 | 4.78 |
| 1 | 4.55 |
| 2 | 4.30 |
| 5 | 4.10 |
| 10 | 4.25 |
| 30 | 4.50 |
Then in any cell, type:
=InterpolateYield(3, A2:A8, B2:B8)
This returns 4.1667%, the linearly interpolated yield for a 3-year maturity between the 2Y (4.30%) and 5Y (4.10%) benchmarks.
| Target Maturity | Interpolated Yield |
|---|---|
| 0.75 years | 4.665% |
| 3 years | 4.167% |
| 7 years | 4.160% |
| 15 years | 4.313% |
| 20 years | 4.375% |
Key Insight: Linear interpolation on yields is the simplest approach. Production systems typically use cubic spline interpolation or Nelson-Siegel models, which produce smoother curves. But linear interpolation is perfectly adequate for quick estimates and sanity checks.
If a trader asks “what’s the 7-year yield?” and you say “let me fit a Nelson-Siegel-Svensson model,” they will throw something at you. Just interpolate linearly and give them the number. You can be precise after market close.
Project 4: Automated Email Report¶
At the end of each day, you want to email a summary of the P&L report to the team. VBA can automate this using Outlook.
Option Explicit
Sub EmailPnLReport()
Dim olApp As Object
Dim olMail As Object
Dim totalPnL As Double
Dim reportDate As String
' Get P&L from the report sheet
totalPnL = Worksheets("P&L Report").Cells( _
Worksheets("P&L Report").Cells(Rows.Count, 1).End(xlUp).Row - 3, _
7).Value
reportDate = Format(Date, "dd-mmm-yyyy")
' Create Outlook email
Set olApp = CreateObject("Outlook.Application")
Set olMail = olApp.CreateItem(0)
With olMail
.To = "trading-desk@example.com"
.CC = "risk-team@example.com"
.Subject = "Daily P&L Report - " & reportDate
.HTMLBody = "<h2>Daily P&L Summary</h2>" & _
"<p>Date: " & reportDate & "</p>" & _
"<p><b>Total P&L: " & Format(totalPnL, "$#,##0.00") & _
"</b></p>" & _
"<p>Full report attached.</p>" & _
"<p>This is an automated message.</p>"
' Attach the workbook
.Attachments.Add ThisWorkbook.FullName
' Display for review (use .Send to send automatically)
.Display
End With
Set olMail = Nothing
Set olApp = Nothing
MsgBox "Email prepared!", vbInformation
End Sub
Never use .Send on the first attempt. Always use .Display so you can review the email before it goes out. One rogue VBA macro sending 400 emails to the CFO is a career-defining moment, and not in a good way.
Performance Tips: Making VBA Not Terrible¶
VBA’s default behavior is to update the screen and recalculate formulas after every single cell change. This makes loops painfully slow. Here is how to fix that.
The Speed Trifecta¶
Sub FastMacro()
' Turn off screen updating, calculations, and events
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
' === Your actual code goes here ===
Dim i As Long
For i = 1 To 100000
Cells(i, 1).Value = i * 2
Next i
' === End of actual code ===
' ALWAYS turn them back on (use error handling in production)
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
End Sub
Performance Comparison¶
| Operation (100,000 rows) | Without Optimization | With Optimization |
|---|---|---|
| Write values to cells | 45 seconds | 2 seconds |
| Read and process cells | 30 seconds | 1.5 seconds |
| Format cells | 60 seconds | 3 seconds |
That is a 20x to 30x improvement. Not bad for three lines of code.
Use Arrays for Bulk Operations¶
Instead of reading cells one by one, load the entire range into an array, process it, and write it back.
Sub ArrayProcessing()
Dim data As Variant
Dim results() As Variant
Dim i As Long
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
' Read entire range into array (instant)
data = Range("A1:D" & lastRow).Value
' Process in memory (fast)
ReDim results(1 To UBound(data, 1), 1 To 1)
For i = 1 To UBound(data, 1)
results(i, 1) = data(i, 3) * data(i, 4) ' Qty * Price
Next i
' Write results back in one operation (fast)
Range("E1:E" & lastRow).Value = results
End Sub
Key Insight: Reading and writing cells individually is the number one performance killer in VBA. A single
Range.Value = arraycall writing 100,000 values is 50 to 100 times faster than 100,000 individualCells(i, j).Value = xcalls. Always work with arrays for large datasets.
Think of it this way. You would not carry groceries from the car one item at a time. You would grab as many bags as possible. VBA arrays are the grocery bags of data processing.
Error Handling: Because Things Will Break¶
VBA without error handling is a ticking time bomb. Here is the standard pattern:
Sub RobustMacro()
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' === Your code here ===
Dim price As Double
price = Range("B2").Value
If price <= 0 Then
Err.Raise vbObjectError + 1, , "Invalid price: " & price
End If
' ... more processing ...
CleanExit:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Exit Sub
ErrorHandler:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Macro Error"
Resume CleanExit
End Sub
The CleanExit label ensures that screen updating and calculation are always restored, even if an error occurs. Without this pattern, a crash can leave your Excel session frozen with calculations turned off. And you will spend 30 minutes wondering why your formulas are not updating before realizing the macro crashed mid-execution.
“Why is nothing calculating?” is the VBA developer’s equivalent of “is it plugged in?” The answer is almost always that a crashed macro left Application.Calculation = xlCalculationManual.
Common Pitfalls¶
Not using Option Explicit. Undeclared variables default to Variant type. A typo in a variable name silently creates a new variable initialized to Empty. Your code runs without errors and produces wrong results. This is the worst kind of bug.
Using Integer instead of Long for row numbers. Integer overflows at 32,767. Excel has 1,048,576 rows. Use Long for anything that could be a row number.
Hardcoding row numbers. Never write
Range("A2:A150")when the data might grow. Always find the last row dynamically.Forgetting to restore Application settings. If your macro crashes between
ScreenUpdating = FalseandScreenUpdating = True, Excel appears frozen. Always use error handlers.Selecting and activating everything.
Range("A1").Selectfollowed bySelection.Value = 5is the macro recorder’s favorite pattern. Never do this. Just writeRange("A1").Value = 5. It is faster and cleaner.Not handling empty cells. An empty cell returns Empty (a Variant). Doing math on Empty gives zero, which might silently corrupt your calculations. Always validate inputs.
Wrapping Up¶
VBA is not winning any beauty contests. It has no package manager, no type inference, no lambda functions (well, it got them in 2021 but nobody noticed), and its debugging experience is from the 1990s. But it runs on every Windows desktop in every bank, fund, and trading firm on the planet. It integrates natively with the tool that finance professionals spend their entire day in. And it turns repetitive, error-prone manual tasks into one-click automations.
The bond pricer, the P&L report, the yield curve interpolator, and the email automation we built today are not toy examples. They are the kinds of tools that actually get used on trading desks. The key is writing them properly: with Option Explicit, error handling, performance optimization, and clear structure.
Learn VBA. Not because it is the best language, but because it is the most useful one in the room where the money is.
Cheat Sheet¶
Key Questions & Answers¶
Why VBA instead of Python for finance tasks?¶
VBA runs inside Excel, which is already on every desk. No installation, no IT approval, no deployment pipeline. Traders live in Excel and want their tools there. VBA is not better than Python for computation, but it is better for “I need this automated in the spreadsheet I already use.”
How do I make VBA macros run faster?¶
Three things: set
Application.ScreenUpdating = False, setApplication.Calculation = xlCalculationManual, and use arrays instead of cell-by-cell operations. These alone can give you 20x to 100x speedups. Always restore these settings when done, using error handlers to guarantee cleanup.
What is Option Explicit and why should I always use it?¶
Option Explicitforces you to declare all variables withDim. Without it, a typo likestockPircesilently creates a new empty variable instead of throwing an error. This leads to bugs that are nearly impossible to find. PutOption Explicitat the top of every module. No exceptions.
How do I handle errors properly in VBA?¶
Use
On Error GoTo ErrorHandlerat the start, aCleanExitlabel for cleanup code, and anErrorHandlerlabel that displays the error and resumes to CleanExit. This pattern ensures Application settings (ScreenUpdating, Calculation) are always restored, even when a macro crashes.
Key Concepts at a Glance¶
| Concept | Summary |
|---|---|
| VBA Editor access | Alt + F11 to open the Visual Basic Editor |
| Option Explicit | Forces variable declaration, prevents typo bugs |
| Long vs Integer | Always use Long for row numbers (Integer overflows at 32,767) |
| Find last row | Cells(Rows.Count, 1).End(xlUp).Row |
| Speed optimization | Disable ScreenUpdating + Manual Calculation + Arrays |
| Array bulk read | data = Range("A1:D100").Value loads entire range at once |
| Array bulk write | Range("E1:E100").Value = results writes entire array at once |
| Error handling | On Error GoTo, CleanExit, ErrorHandler pattern |
| Cell reference | Range("B2").Value or Cells(row, col).Value |
| Custom functions | Function keyword creates UDFs usable in worksheet formulas |
| COM automation | CreateObject("Outlook.Application") to control other Office apps |
| Bond pricing | PV of coupons + PV of face value, discounted at YTM |
| Interpolation | Find two surrounding points, apply linear formula |
| Variant type | Avoid when possible, use specific types for safety and speed |
Sources & Further Reading¶
- Walkenbach, J., Excel VBA Programming for Dummies, Wiley
- Jelen, B. & Syrstad, T., VBA and Macros for Microsoft 365, Que Publishing
- Urtone, R., Financial Modeling in Excel For Dummies, Wiley
- Microsoft Docs, VBA Language Reference
- Microsoft Docs, Excel Object Model Reference
- Benninga, S., Financial Modeling, MIT Press
- Investopedia, Bond Valuation
- ExcelJet, VBA Tutorial
- Wise Owl Tutorials, Excel VBA Introduction