The strategy uses Bitcoin’s moving averages (20-day, 1-day, 2-day, 4-day, 10-day) to guide buy or sell decisions. The portfolio is rebalanced daily with 10% actively traded and sub-strategies equally weighted.

I. STRATEGY IN A NUTSHELL

Trades Bitcoin using multiple moving averages (1-, 2-, 4-, 10-, and 20-day). Buy when price > MA, sell to risk-free when below. Sub-strategies equally weighted, 10% of portfolio actively traded, rebalanced daily.

II. ECONOMIC RATIONALE

Moving averages provide predictive power for Bitcoin prices, reducing drawdowns and enhancing risk-adjusted returns. Combining multiple MA signals improves timing and performance, outperforming macroeconomic predictors.

III. SOURCE PAPER

 Bitcoin: Learning and Predictability via Technical Analysis: Evidence from Bitcoin and Stocks with Hard-to- Value Fundamentals [Click to Open PDF]

Detzel, Andrew L., Baylor University – Hankamer School of Business; Liu, Hong, Washington University in St. Louis – Olin Business School; Strauss, Jack, Fudan University – China Institute of Economics and Finance; Zhou, Guofu, University of Denver – Daniels College of Business; Zhu, Yingzi, Washington University in St. Louis – John M. Olin Business School; Tsinghua University – School of Economics & Management

<Abstract>

What predicts returns on assets with “hard-to-value” fundamentals, such as Bitcoin and stocks in new industries? We propose an equilibrium model that shows how rational learning enables return predictability through technical analysis. We document that ratios of prices to their moving averages forecast daily Bitcoin returns in- and out-of sample. Trading strategies based on these ratios generate an economically significant alpha and Sharpe ratio gains relative to a buy-and-hold position. Similar results hold for small-cap, young-firm, and low-analyst-coverage stocks as well as NASDAQ stocks during the dotcom era.

IV. BACKTEST PERFORMANCE

Annualised Return10.03%
Volatility4.97%
Beta0.033
Sharpe Ratio 2.45
Sortino Ratio 0.571
Maximum Drawdown-4.01%
Win Rate51%

V. FULL PYTHON CODE

from AlgorithmImports import *
class MovingAverageCryptocurrencies(QCAlgorithm):
    def Initialize(self):
        self.set_start_date(2015, 1, 1)
        self.set_cash(100_000)
        self.symbol: Symbol = self.add_crypto('BTCUSD', Resolution.DAILY, Market.BITFINEX).symbol
        self.securities[self.symbol].set_fee_model(CustomFeeModel())
        
        self.MAs: List[SimpleMovingAverage] = [
            self.SMA(self.symbol, 1, Resolution.Daily),
            self.SMA(self.symbol, 2, Resolution.Daily),
            self.SMA(self.symbol, 4, Resolution.Daily),
            self.SMA(self.symbol, 10, Resolution.Daily),
            self.SMA(self.symbol, 20, Resolution.Daily)
        ]
            
    def OnData(self, slice: Slice) -> None:
        if not self.symbol in slice: return
            
        price: float = slice[self.symbol].Value
        if price == 0: return
        long_signal_count: int = 0
        for ma in self.MAs:
            if ma.IsReady:
                if price > ma.Current.Value:
                    long_signal_count += 1
        else:
            self.Liquidate()
        
        w: float = (0.1 / len(self.MAs)) * long_signal_count
        self.SetHoldings(self.symbol, w)
                
# Custom fee model
class CustomFeeModel(FeeModel):
    def GetOrderFee(self, parameters):
        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
        return OrderFee(CashAmount(fee, "USD"))

VI. Backtest Performance

Leave a Reply

Discover more from Quant Buffet

Subscribe now to keep reading and get access to the full archive.

Continue reading