This paper carries out a comprehensive examination of technical trading rules in cryptocurrency markets, using data from two Bitcoin markets and three other popular cryptocurrencies. We employ almost 15,000 technical trading rules from the main five classes of technical trading rules and find significant predictability and profitability for each class of technical trading rule in each cryptocurrency. We find that the breakeven transaction costs are substantially higher than those typically found in cryptocurrency markets. To safeguard against data-snooping, we implement a number of multiple hypothesis procedures which confirms our findings that technical trading rules do offer significant predictive power and profitability to investors. We also show that the technical trading rules offer substantially higher risk-adjusted returns than the simple buy-and-hold strategy, showing protection against lengthy and severe drawdowns associated with cryptocurrency markets. However there is no predictability for Bitcoin in the out-of-sample period, although predictability remains in other cryptocurrency markets.
Keywords: Technical Analysis, Cryptocurrencies, Bitcoin, Data-Snooping, Market Efficiency
- Target asset for investment: Exclusively Bitcoin.
- Obtain daily Bitcoin price data from: Coindesk.com.
- Determine the 10-day moving average on day t: Average of the prices from the last 10 days (not counting day t).
- Purchase indicator: Buy Bitcoin when the ratio of (price on day t-1) to (10-day moving average) exceeds 1.
- Sale indicator: Liquidate Bitcoin and move to a risk-free asset when the ratio of (price on day t-1) to (10-day moving average) is less than 1.
- Adjust positions daily.
- Only trade actively with 10% of the total portfolio.
import backtrader as bt class MovingAverageStrategy(bt.Strategy): params = dict( ma_period=10, active_pct=0.1 ) def __init__(self): self.data_close = self.datas.close self.sma = bt.indicators.SimpleMovingAverage( self.datas, period=self.params.ma_period) def next(self): position_size = self.broker.get_value() * self.params.active_pct if not self.position: if self.data_close[-1] > self.sma[-1]: self.buy(size=position_size / self.data_close) else: if self.data_close[-1] < self.sma[-1]: self.sell(size=self.position.size) if __name__ == '__main__': cerebro = bt.Cerebro() data = bt.feeds.GenericCSVData( dataname='path/to/your/bitcoin_data.csv', dtformat=('%Y-%m-%d'), datetime=0, high=2, low=3, open=1, close=4, volume=5, openinterest=-1 ) cerebro.adddata(data) cerebro.addstrategy(MovingAverageStrategy) cerebro.broker.setcash(100000.0) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.run() print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
Remember to replace ‘path/to/your/bitcoin_data.csv’ with the actual path to your Bitcoin daily price data downloaded from Coindesk.com.