
“该策略使用波罗的海油轮指数移动平均线交易油轮主导股票,当短期平均线超过长期平均线时买入,反之则卖出,在信号之间持有头寸。”
资产类别: 股票 | 地区: 全球 | 周期: 每月 | 市场: 股票 | 关键词: 干散货指数、油轮、航运
I. 策略概要
该策略的目标是油轮主导公司的股票(例如,DHT Holding、Teekay、Tsakos Energy Nav和Capital Product Partners)。它使用波罗的海油轮指数(BT(t))并应用两个移动平均线:六周长期平均线(MA(6))和一周滞后短期平均线(MA(1))。当MA(1)超过MA(6)时,出现买入信号,表明价格加速上涨;当MA(1)跌破MA(6)时,出现卖出信号,表明价格减速下跌。在交叉点之间,该策略持有其头寸,在买入信号后买入,并持有至卖出信号。这种方法系统地跟踪价格动量,以优化油轮股票的交易决策。
II. 策略合理性
由于该行业的全球化性质,航运股票表现出独特的特征。与其他行业不同,市场贝塔和国家特定风险与航运股票的相关性较低,而全球风险因素,尤其是运费(例如,波罗的海油轮指数),至关重要。运费显著影响航运公司的收入和业绩,在油轮市场运费和航运股票回报之间建立了强大的长期关系。研究表明,波罗的海油轮指数和航运股票投资组合是协整的,从而可以基于这种关联性制定有利可图的交易策略。一种使用协整和移动平均线提出的策略优于简单的买入并持有方法。但是,由于潜在的局限性,建议在应用此策略时要谨慎。
III. 来源论文
A Cointegrating Stock Trading Strategy for Tanker Shipping Companies [点击查看论文]
- 尼克塔里奥斯·A·米海尔(Nektarios A. Michail)与康斯坦丁诺斯·D·梅拉斯(Konstantinos D. Melas),塞浦路斯科技大学;塞浦路斯中央银行;希腊大都会学院商学与经济学院;西马其顿大学
<摘要>
我们提出了一种在美国市场交易上市航运公司投资组合的策略。特别是,我们估计了油轮航运公司投资组合的每周股票市场回报与波罗的海油轮指数之间的协整关系,利用了运费与航运公司股票市场表现之间的密切关系。我们的结果表明,基于协整关系和简单移动平均线规则的交易策略在不同的投资期限内,通常以非常大的优势,优于标准的买入并持有策略。


IV. 回测表现
| 年化回报 | 3.86% |
| 波动率 | N/A |
| β值 | -0.008 |
| 夏普比率 | N/A |
| 索提诺比率 | N/A |
| 最大回撤 | N/A |
| 胜率 | 46% |
V. 完整的 Python 代码
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"))