Broker API HubMenu

Stage 1 of 4, lesson 5 of 31. Beginner

Write a function: size a position from the risk you choose

Wrap a calculation in a function you can reuse and test, using position sizing as the example. It introduces functions, parameters, return values and raising an error.

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 lessons on variables, if statements and loops. No broker account.

A function is a named piece of code that takes inputs and hands back an answer. Once a calculation works, putting it in a function means you write it once and trust it everywhere.

The example is one every trader meets: given an account balance, the share of it you are prepared to lose on one trade, and how far away your stop is, how large can the position be? The arithmetic is short. The point is to see it written once, named clearly and reused.

Notice the last part. A good function refuses an input that makes no sense, such as a stop distance of zero, instead of quietly returning a wrong number. In trading code, a loud failure is far cheaper than a silent one.

The figures are examples chosen to make the arithmetic easy to follow. They are not a suggestion about how much to risk.

The code

# Write a function, and use it to size a position from the risk you choose.
# No broker, no account, no internet. The numbers are examples, not advice.


def position_size(account_balance, risk_percent, stop_distance_points, value_per_point=1.0):
    """How many units to trade so that hitting the stop loses risk_percent of the account."""
    if stop_distance_points <= 0:
        raise ValueError("The stop distance must be more than zero.")
    money_at_risk = account_balance * risk_percent / 100
    return money_at_risk / (stop_distance_points * value_per_point)


balance = 10000
for risk in (0.5, 1, 2):
    size = position_size(balance, risk, stop_distance_points=25)
    print("Risking", risk, "percent with a 25 point stop:", round(size, 2), "per point")

# The same risk with a wider stop means a smaller position.
print("Same 1 percent, 100 point stop:", round(position_size(balance, 1, 100), 2), "per point")

# A function should refuse nonsense instead of returning a wrong answer.
try:
    position_size(balance, 1, 0)
except ValueError as problem:
    print("Refused:", problem)

What you should see

Risking 0.5 percent with a 25 point stop: 2.0 per point
Risking 1 percent with a 25 point stop: 4.0 per point
Risking 2 percent with a 25 point stop: 8.0 per point
Same 1 percent, 100 point stop: 1.0 per point
Refused: The stop distance must be more than zero.

Run with Python 3.12 on Windows. 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.

What happens when the function is called with a stop distance of 0?

It raises a ValueError before doing any arithmetic. The try and except at the bottom catches it and prints Refused with the message.

Most calls pass three values, but the function has four parameters. Where does the fourth come from?

value_per_point has a default of 1.0 in the def line. When the caller leaves it out, the default is used.

With a 25 point stop, 1 percent gives 4.0 per point. Why does a 100 point stop give 1.0?

The money at risk is the same, 100. It is divided by the stop distance, so a stop four times as far away gives a position a quarter of the size.

Exercise

Add one line that sizes the same 1 percent risk with a 25 point stop on a market where each point is worth 10, by passing value_per_point. Print it before the part that tests the refusal.

What the changed script prints
Risking 0.5 percent with a 25 point stop: 2.0 per point
Risking 1 percent with a 25 point stop: 4.0 per point
Risking 2 percent with a 25 point stop: 8.0 per point
Same 1 percent, 100 point stop: 1.0 per point
Same 1 percent, 25 point stop, 10 a point: 0.4 per point
Refused: The stop distance must be more than zero.

Captured from a run of the solution on . Run with Python 3.12 on Windows. No network and no account.

One solution
# Exercise solution: the lesson script with the one change the exercise asks for.
# Write a function, and use it to size a position from the risk you choose.
# No broker, no account, no internet. The numbers are examples, not advice.


def position_size(account_balance, risk_percent, stop_distance_points, value_per_point=1.0):
    """How many units to trade so that hitting the stop loses risk_percent of the account."""
    if stop_distance_points <= 0:
        raise ValueError("The stop distance must be more than zero.")
    money_at_risk = account_balance * risk_percent / 100
    return money_at_risk / (stop_distance_points * value_per_point)


balance = 10000
for risk in (0.5, 1, 2):
    size = position_size(balance, risk, stop_distance_points=25)
    print("Risking", risk, "percent with a 25 point stop:", round(size, 2), "per point")

# The same risk with a wider stop means a smaller position.
print("Same 1 percent, 100 point stop:", round(position_size(balance, 1, 100), 2), "per point")

print("Same 1 percent, 25 point stop, 10 a point:", round(position_size(balance, 1, 25, value_per_point=10), 2), "per point")

# A function should refuse nonsense instead of returning a wrong answer.
try:
    position_size(balance, 1, 0)
except ValueError as problem:
    print("Refused:", problem)

Your progress

Next: Test your functions

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 1 of 4: First steps. Values, decisions, loops and functions, and the habit of testing what you wrote. No files and no account.

  1. First Python script
  2. Variables and types
  3. If and comparisons
  4. Lists and loops
  5. Functions and sizingYou are here
  6. Test your functions

The whole path, every stage

Back: Lists and loopsNext: Test your functions