Overnight Seasonality in Bitcoin
Log in to collectAcademic paper
Seasonality, Trend-following, and Mean reversion in Bitcoin
Matus Padysak; Radovan Vojtko
- SKComenius University Bratislava
- ?Comenius University - Faculty of Mathematics, Physics and Informatics
- ?Quantpedia.com
Strategy in a nutshell
Universe: Bitcoin (Gemini exchange). Long BTC at 22:00 UTC, hold for 2 hours, then close the position.
Economic rationale
The BTC 22:00–24:00 seasonality may arise because all major traditional markets are closed, leaving BTC as one of the few actively traded assets. Statistical analysis shows significant positive returns during this period, with negligible negative returns, making it a favorable short-term window.
Backtest performance
Annualised return33.01%
Volatility20.93%
Beta0.068
Sharpe ratio1.49
Sortino ratio1.06
Maximum drawdown-22.45%
Win rate52%
Full Python code
from AlgorithmImports import *
# endregion
class OvernightSeasonalityinBitcoin(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2016, 1, 1)
self.SetCash(100000)
# NOTE Coinbase Pro, CoinAPI, and Bitfinex data is all set in UTC Time. This means that when accessing data from this brokerage, all data will be time stamped in UTC Time.
self.crypto = self.AddCrypto("BTCUSD", Resolution.Minute, Market.Bitfinex)
self.crypto.SetLeverage(10)
self.crypto.SetFeeModel(CustomFeeModel())
self.crypto = self.crypto.Symbol
self.open_trade_hour:int = 22
self.close_trade_hour:int = 0
def OnData(self, data):
if self.crypto in data and data[self.crypto]:
time:datetime.datetime = self.UtcTime
# open long position
if time.hour == self.open_trade_hour and time.minute == 0:
self.SetHoldings(self.crypto, 1)
# close position
if time.hour == self.close_trade_hour and time.minute == 0:
if self.Portfolio[self.crypto].Invested:
self.Liquidate(self.crypto)
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))