The strategy involves trading Bitcoin-dollar pairs across exchanges, using price premiums and discounts. It buys Bitcoin in markets with low discounts and sells in Bitfinex, rebalanced daily with equally weighted portfolios.

I. STRATEGY IN A NUTSHELL

The strategy trades Bitcoin-dollar pairs across multiple exchanges, treating each pair as a separate asset. For each exchange, the Bitcoin price is compared to Bitfinex, and a discount is computed. Assets are ranked by discount and grouped into five portfolios. The strategy buys Bitcoin on exchanges with the lowest discounts (highest premiums) and sells on Bitfinex. Portfolios are equally weighted, rebalanced daily, and use Bitcoin futures with borrowed dollars, including interest.

II. ECONOMIC RATIONALE

Bitcoin prices differ across exchanges due to market inefficiencies, despite the law of one price. Pure arbitrage is costly due to fees and delays, but exploiting these price discrepancies remains profitable after trading costs, allowing investors to capture substantial returns from persistent exchange-level price gaps.

III. SOURCE PAPER

Cryptomarket Discounts [Click to Open PDF]

Borri, Nicola and Shakhnov, Kirill, LUISS University – Department of Economics and Finance, University of Surrey.

<Abstract>

This paper studies the efficiency of the cryptocurrency market by looking at the distribution
of bitcoin prices over time and across exchange-currency pairs. We document persistent
differences in relative bitcoin prices (or discounts), with a half-life of 1 day, and a distribution
which is leptokurtic, skewed to the right, with a standard deviation of 3.9%. The variability
of discounts is larger in countries with tighter capital controls due to the combined effect
of market segmentation and local supply and demand shocks, which we relate to locationspecific mining activities and investor attention.

IV. BACKTEST PERFORMANCE

Annualised Return17.82%
Volatility3.28%
Beta-0.005
Sharpe Ratio 4.21
Sortino RatioN/A
Maximum DrawdownN/A
Win Rate62%

V. FULL PYTHON CODE

from AlgorithmImports import *
import data_tools
# endregion
class CryptomarketDiscounts(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2015, 1, 1)
        self.SetCash(100000)
        # exchanges
        tickers:list[str] = [
            'ABUCOINS_BTCUSD', 'BITBAY_BTCUSD', 'BITSTAMP_BTCUSD', 'BITTREX_BTCUSD',
            'CEX_BTCUSD', 'COINBASE_BTCUSD', 'EXMO_BTCUSD', 'GEMINI_BTCUSD',
            'HITBTC_BTCUSD', 'ITBIT_BTCUSD', 'KRAKEN_BTCUSD', 'OKCOIN_BTCUSD', 
            'YOBIT_BTCUSD'
        ]
        bitfinex_btc_ticker:str = 'BITFINEX_BTCUSD'
        self.quantile:int = 5
        self.portfolio_percentage:float = .1
        self.exchange_btc_symbols:list[Symbol] = []
        # subscribe symbols
        for ticker in tickers + [bitfinex_btc_ticker]:
            security:Security = self.AddData(data_tools.QuantpediaBTCExchanges, ticker, Resolution.Daily)
            security.SetFeeModel(data_tools.CustomFeeModel())
            security.SetLeverage(5)
            if ticker == bitfinex_btc_ticker:
                self.bitfinex_btc_symbol:Symbol = security.Symbol
            else:
                self.exchange_btc_symbols.append(security.Symbol)
    def OnData(self, data: Slice):
        premium_by_symbol:dict[Symbol, float] = {}
        # calculate discount (premium)
        if data.ContainsKey(self.bitfinex_btc_symbol):
            bitfinex_btc_price:float = data[self.bitfinex_btc_symbol].Value
            for exch_symbol in self.exchange_btc_symbols:
                if data.ContainsKey(exch_symbol):
                    exch_price:float = data[exch_symbol].Value
                    
                    premium:float = exch_price / bitfinex_btc_price - 1
                    premium_by_symbol[exch_symbol] = premium
        
        if len(premium_by_symbol) < self.quantile:
            self.Liquidate()
            return
        quantile:int = int(len(premium_by_symbol) / self.quantile)
        sorted_by_discount:list[Symbol] = [x[0] for x in sorted(premium_by_symbol.items(), key=lambda item: item[1])]
        # investing in the markets with the highest discounts
        long_leg:list[Symbol] = sorted_by_discount[:quantile]
        long_length = len(long_leg)
        # liquidate
        invested = [x.Key for x in self.Portfolio if x.Value.Invested]
        for exch_symbol in invested:
            if exch_symbol not in long_leg and exch_symbol != self.bitfinex_btc_symbol:
                self.Liquidate(exch_symbol)
        # trade arbitrage
        for exch_symbol in long_leg:
            self.SetHoldings(exch_symbol, (1 / long_length) * self.portfolio_percentage)
        self.SetHoldings(self.bitfinex_btc_symbol, -1 * self.portfolio_percentage)

Leave a Reply

Discover more from Quant Buffet

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

Continue reading