Overall Statistics
Total Trades
339
Average Win
3.18%
Average Loss
-2.79%
Compounding Annual Return
409.296%
Drawdown
21.000%
Expectancy
0.354
Net Profit
363.331%
Sharpe Ratio
2.64
Loss Rate
37%
Win Rate
63%
Profit-Loss Ratio
1.14
Alpha
0.344
Beta
0.427
Annual Standard Deviation
0.465
Annual Variance
0.216
Information Ratio
-1.561
Tracking Error
0.538
Treynor Ratio
2.873
Total Fees
$0.00
import decimal as d

# shorthands for units
K, M, B = 10**3, 10**6, 10**9

### <summary>
### GDAX Playground.
### </summary>
### <meta name="tag" content="crypto bitcoin GDAX SetHoldings order PostType playground" />
class GDAXPlaygroundAlgorithm(QCAlgorithm):

    def Initialize(self):
        
        #-- Parameters ---------------------------------------------------------
        self.crypto = "BTCUSD"
        self.cash = 10*K
        self.SetStartDate(2017, 01, 01)
        resolution = Resolution.Daily
        #-----------------------------------------------------------------------
        
        self.cash = d.Decimal(self.cash)
        self.SetCash(self.cash)
        self.SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash)
        self.AddCrypto(self.crypto, resolution)
        
        #DefaultOrderProperties = GDAXOrderProperties()
        #DefaultOrderProperties.PostType = True
        
        self.SetBenchmark(SecurityType.Crypto, self.crypto)    # doesn't work


    def OnData(self, data):
        
        security = self.Securities[self.crypto]
        quantity = security.Holdings.Quantity
        
        self.Transactions.CancelOpenOrders(self.crypto)    # in case they haven't filled
        # flip from 0% to 100% repeatedly
        self.SetHoldings(self.crypto, 1 if not quantity else 0)
        
        portfolio = self.Portfolio
        self.Plot("Leverage?", portfolio.TotalHoldingsValue / portfolio.TotalPortfolioValue)    # inaccurate
        self.Plot("Price", security.Price)
        self.Plot("Quantity", quantity)

    
    # Override SetHoldings to use limit orders (ratio is of totalPortfolioValue.)
    def SetHoldings(self, symbol, ratio):
        
        security = self.Securities[symbol]
        if not security.IsTradable:
            self.Debug("{} is not tradable.".format(symbol))
            return    # passive fail
        ratio = d.Decimal(ratio)
        price, quantity = security.Price, security.Holdings.Quantity
        
        # Keep 2% Cash    (for the limit order, rounding errors, and safety)
        totalPortfolioValue = self.Portfolio.TotalPortfolioValue * d.Decimal(0.98)
        
        # +0.1% Limit Order
        # (to make sure it executes quickly and without much loss)
        # (if you set the limit large it will act like a market order)
        limit = 1.001
        desiredQuantity = totalPortfolioValue * ratio / price
        orderQuantity = desiredQuantity - quantity
        # limit needs to be inverse when selling
        limitPrice = price * d.Decimal(limit if orderQuantity >= 0 else 1/limit)
        self.Log("Limit Order: {} coins @ ${} per coin".format(orderQuantity, limitPrice))
        self.LimitOrder(self.crypto, orderQuantity, limitPrice)


# END