Overall Statistics
Total Trades
4127
Average Win
0.16%
Average Loss
-0.14%
Compounding Annual Return
7.513%
Drawdown
6.400%
Expectancy
0.157
Net Profit
57.154%
Sharpe Ratio
1.383
Probabilistic Sharpe Ratio
86.123%
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
1.16
Alpha
0.053
Beta
-0.007
Annual Standard Deviation
0.038
Annual Variance
0.001
Information Ratio
-0.32
Tracking Error
0.157
Treynor Ratio
-7.384
Total Fees
$1538.73
Estimated Strategy Capacity
$890000.00
# The investment universe consists of one cryptocurrency – Bitcoin. Daily Bitcoin prices are obtained from the site Coindesk.com. We construct an equally-weight strategy of moving averages. 
# Firstly, compute 20-day moving average at day t as a sum of prices for the previous 20 days (day t is excluded) divided by 20. If the price of bitcoin at time t-1 divided by the 20-day 
# moving average is larger than 1, buy the bitcoin. If it is lower than 1, sell the bitcoin and invest in a risk-free rate at day t. We do the same for 1, 2, 4 and 10 days. The overall 
# strategy is constructed by equally-weighting the five sub-strategies. The final strategy is rebalanced daily, and only 10% of the portfolio is actively traded.
#


class MovingAverageCryptocurrencies(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2015, 1, 1)
        self.SetCash(100000)

        data = self.AddCrypto('BTCUSD', Resolution.Daily, Market.Bitfinex)
        data.SetFeeModel(CustomFeeModel(self))
        self.symbol = data.Symbol
        
        self.MAs = [
            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, data):
        if not self.symbol in data: return
            
        price = data[self.symbol].Value
        if price == 0: return

        long_signal_count = 0
        for ma in self.MAs:
            if ma.IsReady:
                if price > ma.Current.Value:
                    long_signal_count += 1
        else:
            self.Liquidate()
        
        w = (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"))