Stage 2 of 4, lesson 9 of 31. Beginner
Read and write JSON, the format broker APIs speak
Load a JSON file into Python, pick out what you need, write your own JSON file and read it back. It introduces dictionaries, json.load, json.dump, missing keys and invalid JSON.
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 lists and loops. No broker account.
JSON is text laid out as names and values, with lists and further names and values nested inside. It is what nearly every broker API sends and expects, so reading and writing it is the entry ticket to the next stage.
Python's json module turns JSON into things you already know. An object in curly brackets becomes a dictionary, which stores values under names. A list in square brackets becomes a list. The words true, false and null become True, False and None.
The script opens a mock file, builds a smaller summary from the parts it needs, writes that to a new file and reads it back. It also meets the two things that go wrong most: a key that is not there, and text that is not valid JSON at all. The values in the mock file are invented.
Files for this lesson
- mock-positions.json, sample data with invented values
The code
# Read and write JSON: the format almost every broker API speaks.
# Download mock-positions.json from this lesson and keep it beside this script.
# It is a mock: the values are invented.
import json
with open("mock-positions.json") as f:
data = json.load(f) # JSON text becomes Python dictionaries and lists
print("Top level keys:", list(data.keys()))
first = data["positions"][0]["position"]
print("null in the file becomes:", first["limitLevel"])
print("true in the file becomes:", data["_mock"])
print("A missing key with .get:", first.get("trailingStop"), "or with a default:", first.get("trailingStop", "not set"))
# Build a smaller structure of your own from the parts you need.
summary = []
for item in data["positions"]:
summary.append({
"market": item["market"]["instrumentName"],
"direction": item["position"]["direction"],
"size": item["position"]["size"],
"hasStop": item["position"]["stopLevel"] is not None,
"hasLimit": item["position"]["limitLevel"] is not None,
})
# json.dump writes Python values out as JSON. indent makes the file readable.
with open("positions-summary.json", "w") as f:
json.dump({"count": len(summary), "positions": summary}, f, indent=2)
print("Wrote positions-summary.json")
# Read it back to prove that what was written is what was meant.
with open("positions-summary.json") as f:
back = json.load(f)
print("Read back", back["count"], "position:")
print(json.dumps(back["positions"][0], indent=2))
# json.loads reads JSON from text, which is what an API reply is before it is parsed.
reply = '{"errorCode": "error.mock.example"}'
print("Error code:", json.loads(reply)["errorCode"])
# Text that is not valid JSON raises an error you can catch.
try:
json.loads('{"size": 1,}')
except json.JSONDecodeError as problem:
print("Not valid JSON:", problem.msg)What you should see
Top level keys: ['_mock', 'positions']
null in the file becomes: None
true in the file becomes: True
A missing key with .get: None or with a default: not set
Wrote positions-summary.json
Read back 1 position:
{
"market": "FTSE 100 (mock)",
"direction": "BUY",
"size": 1,
"hasStop": true,
"hasLimit": false
}
Error code: error.mock.example
Not valid JSON: Expecting property name enclosed in double quotesRun 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.
What is the difference between json.load and json.loads?
json.load reads from an open file. json.loads reads from text you already hold in a variable, which is how the script reads the short reply with the error code in it.
Why does the script use first.get("trailingStop") and not first["trailingStop"]?
The key is not in the file. Square brackets would stop the program with a KeyError. The get method returns None instead, or the default you pass, which the script shows as not set.
In the summary that was written, hasStop is true and hasLimit is false. Where do those come from?
The script tests whether stopLevel and limitLevel are None. The file has a stop of 7600 and a limit of null, and null becomes None in Python, so the first test is True and the second is False. json.dump writes them back as true and false.
Exercise
Add the market's epic to each entry in the summary, under the name epic, between market and direction. Run it and read the new file.
What the changed script prints
Top level keys: ['_mock', 'positions']
null in the file becomes: None
true in the file becomes: True
A missing key with .get: None or with a default: not set
Wrote positions-summary.json
Read back 1 position:
{
"market": "FTSE 100 (mock)",
"epic": "IX.D.FTSE.DAILY.IP",
"direction": "BUY",
"size": 1,
"hasStop": true,
"hasLimit": false
}
Error code: error.mock.example
Not valid JSON: Expecting property name enclosed in double quotesCaptured 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.
# Read and write JSON: the format almost every broker API speaks.
# Download mock-positions.json from this lesson and keep it beside this script.
# It is a mock: the values are invented.
import json
with open("mock-positions.json") as f:
data = json.load(f) # JSON text becomes Python dictionaries and lists
print("Top level keys:", list(data.keys()))
first = data["positions"][0]["position"]
print("null in the file becomes:", first["limitLevel"])
print("true in the file becomes:", data["_mock"])
print("A missing key with .get:", first.get("trailingStop"), "or with a default:", first.get("trailingStop", "not set"))
# Build a smaller structure of your own from the parts you need.
summary = []
for item in data["positions"]:
summary.append({
"market": item["market"]["instrumentName"],
"epic": item["market"]["epic"],
"direction": item["position"]["direction"],
"size": item["position"]["size"],
"hasStop": item["position"]["stopLevel"] is not None,
"hasLimit": item["position"]["limitLevel"] is not None,
})
# json.dump writes Python values out as JSON. indent makes the file readable.
with open("positions-summary.json", "w") as f:
json.dump({"count": len(summary), "positions": summary}, f, indent=2)
print("Wrote positions-summary.json")
# Read it back to prove that what was written is what was meant.
with open("positions-summary.json") as f:
back = json.load(f)
print("Read back", back["count"], "position:")
print(json.dumps(back["positions"][0], indent=2))
# json.loads reads JSON from text, which is what an API reply is before it is parsed.
reply = '{"errorCode": "error.mock.example"}'
print("Error code:", json.loads(reply)["errorCode"])
# Text that is not valid JSON raises an error you can catch.
try:
json.loads('{"size": 1,}')
except json.JSONDecodeError as problem:
print("Not valid JSON:", problem.msg)Your progress
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.
This browser refused to store anything for this page, so marks cannot be kept here.
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.
- Prices from a fileDone
- Dates and time zonesDone
- Read and write JSONDoneYou are here
- Money with DecimalDone
- Build a trade journalDone
- Measure drawdownDone