Quant BuffetRelax, Not Over Thinking

Using Baltic Dry Index to Trade Tanker Shipping Companies

Log in to collect

Academic paper

A Cointegrating Stock Trading Strategy for Tanker Shipping Companies

AuthorsNektarios Michail; Konstantinos D. Melas

Institute
  • CYCyprus University of Technology
  • GRMetropolitan College
  • GRUniversity of Western Macedonia
  • ?Metropolitan College, Greece - Faculty of Business and Economics

Strategy in a nutshell

Trades tanker-dominant stocks using the Baltic Tanker Index with a moving-average crossover: buys when the one-week lagged MA(1) exceeds the six-week MA(6) and sells when it falls below. Positions are held between signals to capture price momentum.

Economic rationale

Shipping stock returns are closely linked to global freight rates rather than local market risks. The Baltic Tanker Index’s cointegration with tanker stocks enables systematic momentum trading that outperforms buy-and-hold approaches.

Backtest performance

Annualised return3.86%
Beta-0.008
Win rate46%

Full Python code

from AlgorithmImports import *
#endregion
class UsingBalticDryIndexTankerShippingCompanies(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2013, 1, 1)
self.SetCash(100000)

data = self.AddData(QuantpediaEquity, 'BADI', Resolution.Daily)
data.SetFeeModel(CustomFeeModel())
self.symbol = data.Symbol

self.period = 6*5
self.SetWarmUp(self.period)

self.sma_6 = self.SMA(self.symbol, self.period, Resolution.Daily)
self.sma_1 = self.SMA(self.symbol, 5, Resolution.Daily)

def OnData(self, data):
if self.IsWarmingUp: return

if self.sma_6.IsReady and self.sma_1.IsReady:
    if self.sma_1.Current.Value > self.sma_6.Current.Value:
        if not self.Portfolio[self.symbol].IsLong:
            self.SetHoldings(self.symbol, 1)
    else:
        if not self.Portfolio[self.symbol].IsShort:
            self.SetHoldings(self.symbol, -1)
            
# NOTE: IMPORTANT: Data order must be ascending (datewise)
class QuantpediaEquity(PythonData):
def GetSource(self, config, date, isLiveMode):
return SubscriptionDataSource("data.quantpedia.com/backtesting_data/index/BADI.csv".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)
def Reader(self, config, line, date, isLiveMode):
data = QuantpediaEquity()
data.Symbol = config.Symbol

if not line[0].isdigit(): return None
split = line.split(';')

data.Time = datetime.strptime(split[0], "%m/%d/%Y")
data['settle'] = float(split[1])
data.Value = float(split[1])
return data
# Custom fee model
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))