Broker API HubMenu

Stage 2 of 4, lesson 12 of 31. Improver

Measure drawdown and losing runs

Track a running balance through a list of trades and find the worst fall from a high and the longest losing run. It introduces keeping state inside a loop.

Independent and unofficialCode run

Risk warning: CFDs and spread bets are complex instruments and come with a high risk of losing money rapidly due to leverage. You can lose money on these products, and each provider publishes its own loss figure under FCA rules. You should consider whether you understand how they work and whether you can afford to take the high risk of losing your money. Automated and API trading can amplify losses through bugs, connectivity failures and runaway orders.

You need: The trade journal lesson. No broker account.

A final total hides how you got there. Two records with the same total can feel completely different to live through: one climbs steadily, the other falls a long way first.

Drawdown is the measure of that fall: the largest drop from a high point to a later low. The script walks through the trades in order, remembers the highest balance seen so far, and checks at every step how far below it the balance now sits.

This is the pattern called keeping state: a few variables that carry what you have learned so far from one pass of the loop to the next. Almost every measurement over a series of trades or prices is built this way.

Files for this lesson

The code

# Measure the worst losing run, not just the final total.
# Uses sample-trades.csv from the trade journal lesson. The trades are invented.
import csv

profits = []
with open("sample-trades.csv", newline="") as f:
    for row in csv.DictReader(f):
        entry, exit_price, size = float(row["entry"]), float(row["exit"]), float(row["size"])
        points = exit_price - entry if row["direction"] == "BUY" else entry - exit_price
        profits.append(points * size)

balance = 0.0
peak = 0.0
worst_drawdown = 0.0
longest_losing_run = 0
current_run = 0

for profit in profits:
    balance += profit
    peak = max(peak, balance)                       # the highest the balance has been so far
    worst_drawdown = max(worst_drawdown, peak - balance)   # how far below that peak we are now
    current_run = current_run + 1 if profit < 0 else 0
    longest_losing_run = max(longest_losing_run, current_run)

print("Final total:", round(balance, 2))
print("Highest point reached:", round(peak, 2))
print("Worst drop from a high:", round(worst_drawdown, 2))
print("Longest run of losing trades:", longest_losing_run)

What you should see

Final total: 9.8
Highest point reached: 19.0
Worst drop from a high: 18.4
Longest run of losing trades: 3

Run with Python 3.12 on Windows against the sample files on this page. No network and no account.

Check yourself

Answer each question from the code above before you open it. The answers were written from the script on this page and what it printed.

The final total is 9.8 but the worst drop is 18.4. How can the drop be larger than the total?

The drop is measured from a high to a later low, not from the start. The balance reached 19.0 at its highest, and at some point it sat 18.4 below a high it had already made.

What sets current_run back to zero?

Any trade that is not a loss. The line adds one when profit is below zero and otherwise sets the run to 0, so a win or a flat trade ends the run.

Does the order of the trades in the file matter to this script?

Yes. The total would be the same in any order, but the peak, the drawdown and the losing run all depend on which trade came after which.

Exercise

Track the longest run of winning trades as well, with two new variables updated inside the loop, and print it as the last line.

What the changed script prints
Final total: 9.8
Highest point reached: 19.0
Worst drop from a high: 18.4
Longest run of losing trades: 3
Longest run of winning trades: 3

Captured from a run of the solution on . Run with Python 3.12 on Windows against the sample files on this page. No network and no account.

One solution
# Exercise solution: the lesson script with the one change the exercise asks for.
# Measure the worst losing run, not just the final total.
# Uses sample-trades.csv from the trade journal lesson. The trades are invented.
import csv

profits = []
with open("sample-trades.csv", newline="") as f:
    for row in csv.DictReader(f):
        entry, exit_price, size = float(row["entry"]), float(row["exit"]), float(row["size"])
        points = exit_price - entry if row["direction"] == "BUY" else entry - exit_price
        profits.append(points * size)

balance = 0.0
peak = 0.0
worst_drawdown = 0.0
longest_losing_run = 0
current_run = 0
win_run = 0
longest_winning_run = 0

for profit in profits:
    balance += profit
    peak = max(peak, balance)                       # the highest the balance has been so far
    worst_drawdown = max(worst_drawdown, peak - balance)   # how far below that peak we are now
    current_run = current_run + 1 if profit < 0 else 0
    longest_losing_run = max(longest_losing_run, current_run)
    win_run = win_run + 1 if profit > 0 else 0
    longest_winning_run = max(longest_winning_run, win_run)

print("Final total:", round(balance, 2))
print("Highest point reached:", round(peak, 2))
print("Worst drop from a high:", round(worst_drawdown, 2))
print("Longest run of losing trades:", longest_losing_run)
print("Longest run of winning trades:", longest_winning_run)

Your progress

Next: Read an API response

Your marks are kept in this browser only, in its local storage. They are not sent anywhere, there is no account, and they will not follow you to another browser or device. To remove them, use Clear my progress on the learning track page, or clear this site's data in your browser's settings. Marking needs JavaScript. With scripts off the track reads the same, without the ticks.

Where this sits in the path

Stage 2 of 4: Working with data. Read prices and trades from files, get dates and money right, and turn a list of trades into a journal.

  1. Prices from a file
  2. Dates and time zones
  3. Read and write JSON
  4. Money with Decimal
  5. Build a trade journal
  6. Measure drawdownYou are here

The whole path, every stage

Repositories to read next

The full repository list

Back: Build a trade journalNext: Read an API response