Cost Analysis of Shipping Propane from the US to the Far East
13 March 2025 - Written by ML
This report analyzes the total cost of shipping propane from the United States (Mont Belvieu, TX) to the Far East (specifically Chiba, Japan). The analysis builds a cost structure by combining the propane spot price at Belvieu with shipping rates, trader profit margins, and import terminal storage fees. This total cost serves as a benchmark to evaluate arbitrage opportunities when compared to propane prices in the Far East.
The analysis includes:
The data for this analysis comes from two primary sources:
The following code loads and prepares the data, aligning propane prices with shipping dates and calculating additional cost components.
# Load clean data
load("C:/Users/ml/project/R/DomEnergyR/data/clean/shipping/avance_data_clean.RData")
load("C:/Users/ml/project/R/DomEnergyR/data/clean/propane/belvieu_propane_data_clean.RData")
# Prepare propane data
p_data <- belvieu_propane_data_clean %>%
rename(Price = Price_USD_per_Tonne) %>%
arrange(Date)
# Helper function to impute propane prices for shipping dates
get_propane_average <- function(s_date, p_data) {
if (s_date %in% p_data$Date) {
return(p_data$Price[p_data$Date == s_date])
}
earlier_dates <- p_data$Date[p_data$Date < s_date]
if (length(earlier_dates) == 0) return(p_data$Price[which.min(p_data$Date)])
d_before <- max(earlier_dates)
later_dates <- p_data$Date[p_data$Date > s_date]
if (length(later_dates) == 0) return(p_data$Price[which.max(p_data$Date)])
d_after <- min(later_dates)
p_before <- p_data$Price[p_data$Date == d_before]
p_after <- p_data$Price[p_data$Date == d_after]
return(mean(c(p_before, p_after), na.rm = TRUE))
}
# Build data frame with cost components
df <- avance_data_clean %>%
rowwise() %>%
mutate(
Belvieu = get_propane_average(Date, p_data),
PriceFlag = ifelse(Date %in% p_data$Date, "Exact", "Imputed"),
TraderProfit = 0.10 * Houston.Chiba,
StorageFees = 0.60 * TraderProfit
) %>%
ungroup()
# Final data frame with total cost
df_final <- df %>%
mutate(
ImportTerminal = StorageFees,
Total = Belvieu + Houston.Chiba + TraderProfit + ImportTerminal
) %>%
select(Date, Belvieu, Houston.Chiba, TraderProfit, ImportTerminal, Total, PriceFlag)
# Display sample of the final data
df_final %>%
head() %>%
kable(caption = "Sample of Cost Components (US$ per Tonne)", format = "html") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)
| Date | Belvieu | Houston.Chiba | TraderProfit | ImportTerminal | Total | PriceFlag |
|---|---|---|---|---|---|---|
| 2024-03-08 | 418.080 | 116 | 11.6 | 6.96 | 552.640 | Exact |
| 2024-03-15 | 420.760 | 134 | 13.4 | 8.04 | 576.200 | Exact |
| 2024-03-22 | 438.448 | 124 | 12.4 | 7.44 | 582.288 | Exact |
| 2024-03-29 | 438.448 | 119 | 11.9 | 7.14 | 576.488 | Imputed |
| 2024-04-05 | 454.528 | 125 | 12.5 | 7.50 | 599.528 | Exact |
| 2024-04-12 | 443.808 | 124 | 12.4 | 7.44 | 587.648 | Exact |
This section presents historical trends of the Mont Belvieu propane spot price and Houston-to-Chiba shipping rates over time. These charts provide context for the cost components analyzed in the subsequent waterfall chart.
# Propane Belvieu price over time (formatted as in EIA script)
latest_propane <- belvieu_propane_data_clean[which.max(belvieu_propane_data_clean$Date), ]
latest_label <- paste0(
"Date: ", format(latest_propane$Date, "%Y-%m-%d"),
"\nPrice: ", dollar(latest_propane$Price_USD_per_Tonne, accuracy = 1)
)
propane_plot <- ggplot(belvieu_propane_data_clean, aes(x = Date, y = Price_USD_per_Tonne)) +
geom_line(aes(color = "Mont Belvieu, TX Propane Spot Price FOB"), size = 1) +
scale_color_manual(values = c("Mont Belvieu, TX Propane Spot Price FOB" = "#1f77b4")) +
scale_y_continuous(labels = dollar_format(prefix = "$", accuracy = 1),
breaks = seq(0, max(belvieu_propane_data_clean$Price_USD_per_Tonne, na.rm = TRUE), length.out = 6)) +
scale_x_date(date_labels = "%Y", breaks = "5 years", expand = expansion(mult = c(0.02, 0.10))) +
labs(title = "Mont Belvieu, TX Propane Spot Price FOB",
subtitle = "Daily Prices in US$ per Tonne (Converted from US$ per Gallon)",
x = "Year",
y = "Price (US$ per Tonne)",
color = "") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 10),
axis.text.x = element_text(angle = 0, hjust = 0.5, size = 8),
legend.position = "top"
) +
geom_label_repel(
data = latest_propane,
aes(label = latest_label, x = Date, y = Price_USD_per_Tonne),
nudge_x = 50,
min.segment.length = 0,
segment.color = "gray50",
arrow = arrow(length = unit(0.015, "npc")),
size = 3,
box.padding = 0.3,
point.padding = 0.5
)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Shipping rates over time (formatted as in Avance script)
shipping_plot <- ggplot(avance_data_clean, aes(x = Date)) +
geom_line(aes(y = Houston.Chiba, color = "Houston-Chiba"), size = 1) +
scale_color_manual(values = c("Houston-Chiba" = "#233450")) +
scale_y_continuous(labels = dollar_format(prefix = "", suffix = "")) +
scale_x_date(date_labels = "%d/%m/%y", breaks = "2 weeks") +
labs(title = "Freight Rates",
subtitle = "Weekly Quotes in US$ per Ton",
x = "Date",
y = "US$ per Ton",
color = "Route") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 10),
axis.text.x = element_text(angle = 90, hjust = 1, size = 8),
legend.position = "top"
) +
annotate("text", x = max(avance_data_clean$Date), y = max(avance_data_clean$Houston.Chiba, na.rm = TRUE),
label = "The above graph shows the quoted freight rates for the US Gulf-Japan route\n(weekly quotes by Clarksons Platou and Poten & Partners).\nThe graph is updated weekly and quoted in $/ton.",
hjust = 1, vjust = 1, size = 3, lineheight = 0.8)
# Display both plots
print(propane_plot)
print(shipping_plot)
The waterfall chart below illustrates the cost components for shipping propane from the US to Chiba, Japan, based on the most recent data point available (2025-03-07). It starts with the Belvieu propane price and sequentially adds shipping fees, trader profit, and import terminal fees to arrive at the total cost.
# Find the latest date
latest_date <- max(df_final$Date)
# Prepare data for waterfall chart based on the latest date
df_waterfall <- df_final %>%
filter(Date == latest_date) %>%
select(Belvieu, Houston.Chiba, TraderProfit, ImportTerminal)
# Create waterfall chart
p <- waterfall(
values = c(df_waterfall$Belvieu, df_waterfall$Houston.Chiba, df_waterfall$TraderProfit, df_waterfall$ImportTerminal),
labels = c("Belvieu Rate", "Shipping Fee", "Trader Profit", "Import Terminal"),
calc_total = TRUE,
total_axis_text = "Total Cost"
) +
ggtitle(paste("US Delivered Propane to Japan (US$ per Tonne) -", format(latest_date, "%Y-%m-%d"))) +
ylab("US$ per Tonne") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
axis.title.y = element_text(size = 12)
)
# Display the chart
print(p)
Below is a summary of the cost components across all available dates, providing insight into their variability and central tendencies.
# Summary statistics for cost components
cost_summary <- df_final %>%
select(Belvieu, Houston.Chiba, TraderProfit, ImportTerminal, Total) %>%
summarise_all(list(
Mean = ~mean(., na.rm = TRUE),
SD = ~sd(., na.rm = TRUE),
Min = ~min(., na.rm = TRUE),
Max = ~max(., na.rm = TRUE)
)) %>%
# First, pivot to long format to separate variable and statistic
pivot_longer(everything(),
names_to = c("Variable", "Statistic"),
names_pattern = "(.*)_(.*)",
values_to = "Value") %>%
# Then, pivot to wide format: variables as rows, statistics as columns
pivot_wider(names_from = "Statistic",
values_from = "Value")
# Display summary table with improved styling
cost_summary %>%
kable(caption = "Summary Statistics of Cost Components (US$ per Tonne)",
format = "html",
digits = 2,
col.names = c("Cost Component", "Mean", "SD", "Min", "Max")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "bordered"),
full_width = FALSE,
position = "center") %>%
column_spec(1, bold = TRUE, width = "2.5in") %>% # Emphasize cost components
column_spec(2:5, width = "1in") %>% # Consistent column widths
add_header_above(c("", "Statistics" = 4)) # Group statistics under a header
| Cost Component | Mean | SD | Min | Max |
|---|---|---|---|---|
| Belvieu | 422.70 | 44.09 | 315.17 | 526.89 |
| Houston.Chiba | 111.02 | 16.42 | 82.00 | 148.00 |
| TraderProfit | 11.10 | 1.64 | 8.20 | 14.80 |
| ImportTerminal | 6.66 | 0.99 | 4.92 | 8.88 |
| Total | 551.48 | 42.66 | 414.93 | 644.05 |
This analysis provides a detailed breakdown of the costs associated with shipping propane from Mont Belvieu, TX, to Chiba, Japan. The time series charts illustrate historical trends in propane prices and shipping rates, while the waterfall chart and summary statistics highlight the relative contributions of the Belvieu propane price, shipping fees, trader profit, and import terminal fees to the total delivered cost as of 2025-03-07. This total cost can be compared to Far East propane prices to assess potential arbitrage opportunities.
Future enhancements could include: - Incorporating Far East propane price data for direct arbitrage comparison. - Analyzing trends in shipping rates and propane prices over time with statistical models. - Sensitivity analysis on trader profit and storage fee assumptions.