Finance Python RandomCharts Visualisations

Shipping Costs Trends

A weekly series of quick random charts made with Python 🐍

The chart of this week is a line bar of the Freightos Baltic Index (FBX) weakly prices showing the year on year pricing trends. The data was published by Freightos Data.

What is Freight and Freight Shipping?

According to FedEx: “any shipment over 150 lbs. is considered freight. Freight shipping is the transportation of goods, commodities and cargo in bulk by ship, aircraft, truck or intermodal via train and road. It can be transported domestically or internationally by land, air or sea.”

Freight is big business. It is a necessity, not a luxury. When transportation system performance decreases, freight-related businesses and their customers are affected in two ways. First, freight assets become less productive. Second, more freight transportation must be consumed to meet the needs of a thriving and expanding economy. Thus, when freight transportation under-performs, the economy pays the price.

U.S. Department of Transportation

The FBX is a daily freight container index issued by the Baltic Exchange and Freightos. It measures global container freight rates — the price at which a cargo is delivered from one point to another– calculating spot rates for 40-foot containers on 12 global tradelanes (FBX includes air and ocean shippings). It is reported as a proxy for shipping stocks, and is currently one of the most widely used freight rate indices.

Year on Year Trend

Today the cost of shipping a 40-foot container (FEU) unit is around \$9,100 according to the Freightos FBX index. The same container shipping cost was around \$3,800 a year ago, and just \$1,500 in January 2020.

🔷 Freight rates started to increase in the second half of 2020. In particular, the FBX crossed the 2,500 U.S. dollars in November 2020.

🔷In 2021, freight rates increased even more dramatically reaching a record price of over 11,000 U.S. dollars in September 2021. 

🔷This trend is mainly due to the impact of the COVID-19 pandemic. Events, such as port closures due to COVID outbreaks, shortages of labor, as well as a lack of shipping containers, disrupted shipping logistics. Besides, government stimulus kept demand for goods high. Actually, an increase in demand took place as consumers spent less in restaurants, hotels, cinemas, etc. and more shopping goods online. This created the perfect storm for freight rates, demand increased at the same time as supply decreased and became more difficult.

Containers are the building blocks of global trade. And at the moment, shippers cannot get enough of them. Surging demand for goods and a shortage of empty containers at Asian ports have sent container-shipping costs rocketing.

The Economist

Python Code

# Author: @Quant_Girl
# Title: Freightos Baltic Index YoY Change
# Source: Freight DATA
# Original plot: https://fbx.freightos.com
# Type: Line/Scatter/Glow

import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import pandas as pd

plt.style.use("dark_background")

colors = [
    '#08F7FE',  # teal/cyan
    '#00ff41',  # matrix green
    '#FE53BB',  # pink
    '#F5D300',  # yellow
]

background_color = '#070c24'
for param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
    plt.rcParams[param] = background_color

# Read Data
df = pd.read_excel('Data/freight.xlsx', parse_dates=['Date'], index_col='Date',
                   engine='openpyxl')

# Figure
fig, ax = plt.subplots(figsize=(12, 12), frameon=True)

# Lines
df.plot(marker='o', color=colors, ax=ax)

# Glow
n_shades = 10
diff_linewidth = 1.05
alpha_value = 0.3 / n_shades
for n in range(1, n_shades + 1):
    df.plot(marker='o',
            linewidth=5 + (diff_linewidth * n), alpha=alpha_value, legend=False, ax=ax, color=colors)

# Area below lines
for column, color in zip(df, colors):
    ax.fill_between(x=df.index, y1=df[column].values, y2=[0] * len(df), color=color, alpha=0.1)

# Grids
ax.grid('y', color='grey')
ax.grid(axis='x', color=background_color)
ax.set_axisbelow(True)

# Spines
ax.spines[['top', 'right', 'left']].set_visible(False)

# Title and Subtitle
ax.text(x=0.05, y=0.93, s="Year on Year Pricing Trends", fontsize=20, fontweight="bold", ha="left",
        transform=fig.transFigure)
ax.text(x=0.05, y=0.90, s="Freightos Baltic Index (FBX): Global Container Freight Index", fontsize=16, ha="left",
        transform=fig.transFigure)

# Labels
ax.set_xlabel('', fontdict={'fontsize': 14}, labelpad=10)
ax.tick_params(axis='x', direction='out', length=10, pad=5, labelsize=12)

ax.set_ylim([0, 13000])
ax.set_yticks(range(0, 13000, 2500))
ax.tick_params(axis="y", direction="out", length=0, pad=5, labelsize=12)
tick = mtick.StrMethodFormatter('${x:,.0f}')
ax.yaxis.set_major_formatter(tick)

# Legend
handles, labels = plt.gca().get_legend_handles_labels()
plt.legend(handles[:2], labels[:2], frameon=False, fontsize=12, labelcolor='white')

# Footnotes
ax.text(x=0.05, y=0.05, s="Source: Freightos DATA - Weakly Prices",
        fontsize=14, ha="left",
        transform=fig.transFigure)

ax.text(x=0.95, y=0.05, s="@Quant_Girl", ha="right",
        transform=fig.transFigure,
        fontdict={'fontsize': 16, 'fontweight': 'bold', 'family': 'sans-serif', 'fontname': 'PT Serif Caption','color': '#ff7096'})

# Show
plt.show()