
“该策略使用基于每日回报的均值和标准差的阈值交易美国原油期货。当价格上涨超过1.6524%时开立多头头寸,当价格下跌低于-1.5784%时开立空头头寸。”
资产类别: 期货 | 地区: 美国 | 周期: 日内 | 市场: 大宗商品 | 关键词: 原油
I. 策略概要
投资范围包括美国原油期货。该策略使用两个阈值来开立头寸:当价格上涨超过开盘价的1.6524%时,开立多头头寸;当价格下跌低于-1.5784%时,开立空头头寸。这些阈值是根据历史时期每日平均回报的均值和标准差计算得出的,使用正态分布设置突破这些水平的5%概率。阈值每日重新计算,头寸在每个交易日结束时以收盘价平仓。
II. 策略合理性
ORB过滤器策略依赖于动量,即资产价格上涨往往会继续上涨,下跌的价格会继续下跌。它也可以用收缩-扩张(C-E)原则来解释,该原则指出市场在温和和大幅价格波动时期之间交替。ORB策略识别并利用扩张日。该研究考察了2001年至2011年期间,在此期间相对较高的波动性可能有助于该策略的盈利能力。这一时间框架有助于解释该策略在这些年间由于有利的市场条件而取得的成功。
III. 来源论文
Assessing the profitability of intraday opening range breakout strategies [点击查看论文]
- 霍姆伯格(Holmberg)、隆巴克(Lonnbark)、伦德斯特伦(Lundstrom),瑞典商业银行(Swedbank)、于默奥大学(Umeå University)
<摘要>
基于历史和公开已知信息的机械交易规则是否有可能跑赢市场?投资者长期以来一直使用此类规则,在本文中,我们测试了开盘区间突破(ORB)策略的交易成功率和盈利能力。采用ORB策略进行交易的投资者试图识别盘中大幅价格波动,并且仅在价格超出预定阈值时进行交易。我们提出了一种基于正态分布回报的ORB策略来识别这些日子,并发现我们的ORB交易策略产生明显高于零的回报,以及相对于公平博弈而言更高的成功率。这种方法相对于传统统计测试的特点是,它涉及给定时间范围内低点、高点、开盘价和收盘价的联合分布。

IV. 回测表现
| 年化回报 | 9.77% |
| 波动率 | N/A |
| β值 | -0.03 |
| 夏普比率 | N/A |
| 索提诺比率 | -0.108 |
| 最大回撤 | N/A |
| 胜率 | 45% |
V. 完整的 Python 代码
import numpy as np
from AlgorithmImports import *
class OpeningRangeBreakoutCrudeOil(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
self.period:int = 21
self.treshhold_value:int = 2
self.future:Future = self.AddFuture(Futures.Energies.CrudeOilWTI, \
Resolution.Minute, \
dataNormalizationMode=DataNormalizationMode.BackwardsRatio, \
contractDepthOffset=0)
self.symbol:Symbol = self.future.Symbol
self.daily_ret:RollingWindow = RollingWindow[float](self.period)
self.recent_open:float = 0
self.day_close_flag:bool = False
self.day_open_flag:bool = False
self.market:Symbol = self.AddEquity('SPY', Resolution.Daily).Symbol
self.Schedule.On(self.DateRules.EveryDay(self.market), self.TimeRules.BeforeMarketClose(self.market, 1), self.DayClose)
self.Schedule.On(self.DateRules.EveryDay(self.market), self.TimeRules.AfterMarketOpen(self.market, 1), self.DayOpen)
def OnData(self, data: Slice) -> None:
# close
if self.day_close_flag:
self.day_close_flag = False
self.Liquidate()
if self.symbol in data and data[self.symbol]:
close:float = data[self.symbol].Close
if close != 0 and self.recent_open != 0 and close != self.recent_open:
todays_ret:float = close / self.recent_open - 1
self.daily_ret.Add(todays_ret)
if self.daily_ret.IsReady:
daily_returns:List[float] = list(self.daily_ret)
mean:float = np.mean(daily_returns)
std:float = np.std(daily_returns)
high_threshhold:float = mean + self.treshhold_value * std
low_threshhold:float = mean - self.treshhold_value * std
if todays_ret > high_threshhold:
if not self.Portfolio.Invested:
self.MarketOrder(self.future.Mapped, 1)
elif todays_ret < low_threshhold:
if not self.Portfolio.Invested:
self.MarketOrder(self.future.Mapped, -1)
self.recent_open = 0
# open
if self.day_open_flag:
self.day_open_flag = False
if self.symbol in data and data[self.symbol]:
self.recent_open = data[self.symbol].Open
def DayClose(self) -> None:
self.day_close_flag = True
def DayOpen(self) -> None:
self.day_open_flag = True