Overall Statistics |
Total Trades 39 Average Win 1.32% Average Loss -0.58% Compounding Annual Return -0.440% Drawdown 6.000% Expectancy -0.270 Net Profit -1.318% Sharpe Ratio -0.086 Probabilistic Sharpe Ratio 1.108% Loss Rate 78% Win Rate 22% Profit-Loss Ratio 2.28 Alpha -0.008 Beta 0.005 Annual Standard Deviation 0.03 Annual Variance 0.001 Information Ratio -1.871 Tracking Error 0.625 Treynor Ratio -0.513 Total Fees $965.83 Estimated Strategy Capacity $280000.00 Lowest Capacity Asset AGLDUSD XJ |
# This guy is using a strategy for cypto that looks at relative strength out of a basket of cryptos to pick the best ones. # Could be a good starting point. # https://www.youtube.com/watch?v=yuZBBX47xK0&list=PLtqRgJ_TIq8Y6YG8G-ETIFW_36mvxMLad&index=14&t=135s import pandas as pd from io import StringIO class JumpingRedOrangeCobra(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 1, 1) # Set Start Date self.SetEndDate(2022, 1, 1) #Set End Date self.SetCash(100000) # Set Strategy Cash # SetBrokerageModel accounts for fees, etc. When commented out Fees are $0, so seems to check out. # Note: test with and without this line, some people said it was screwing up backtests in the forum self.SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash) # Helper variables self.Settings.FreePortfolioValuePercentage = 0.05 # Reserve 5% of the portfolio to always be in cash (helps for paying fees without overdraft, etc.) self.positionSizeUSD = 5000 # Allocation of single position self.rsiEntryThreshold = 70 # RSI Entry Value self.rsiExitThreshold = 60 # RSI Exit Value self.minimumVolume = 1000000 # Min volume for filtering out illiquid cryptos # List of all the USD pairs of cryptos on the exchange (need to figure out if there is a way to do this programatically) # Check this CSV for available coins: https://github.com/QuantConnect/Lean/blob/master/Data/symbol-properties/symbol-properties-database.csv # Manual Universe: # universe = ['BTCUSD', 'LTCUSD', 'ETHUSD', 'YFIUSD', 'MKRUSD', 'LINKUSD', 'UNIUSD', 'BCHUSD'] # Try to pull the universe from the CSV file: WHY DOESN'T THIS WORK!? url = 'https://raw.githubusercontent.com/QuantConnect/Lean/master/Data/symbol-properties/symbol-properties-database.csv' content = self.Download(url) stringData = StringIO(content) df = pd.read_csv(stringData) gdax = df[df["market"].str.contains('gdax')] gdax = gdax[gdax["symbol"].str.endswith("USD")].reset_index() universe = gdax['symbol'].tolist() # Iterate through the list of these tickers using the Pair class attributes below self.pairs = [ Pair(self, ticker, self.minimumVolume) for ticker in universe ] self.SetBenchmark("BTCUSD") # Set benchmark to BTC self.SetWarmup(30) # Set warmup to 30 bars since our SMAs require this length of time to calculate def OnData(self, data): for pair in self.pairs: if not pair.rsi.IsReady: # make sure RSI is ready return # Put symbol and RSI in a local variable since we'll need those in the next few lines symbol = pair.symbol rsi = pair.rsi.Current.Value # Check if we are invested in a given symbol and see if we might want to sell because of low volume or low RSI if self.Portfolio[symbol].Invested: if not pair.Investable(): self.Liquidate(symbol, "Not enough volume") # These tags show up in the orders list elif rsi < self.rsiExitThreshold: self.Liquidate(symbol, "RSI below threshiold") continue # We can now assume we have no active position in the pair in question so we need to see if we should enter it # Is the pair investable (i.e. volume checks)? If not continue out of the for loop. if not pair.Investable(): continue # If the pair passes the investable check, now check to see if the RSI is above our threshold and if we have enough money. If so, buy it if rsi > self.rsiEntryThreshold and self.Portfolio.MarginRemaining > self.positionSizeUSD: self.Buy(symbol, self.positionSizeUSD / self.Securities[symbol].Price) # Since we want to access the properties of the above tickers, create a class to refer to these properties class Pair: def __init__(self, algorithm, ticker, minimumVolumne): self.symbol = algorithm.AddCrypto(ticker, Resolution.Daily, Market.GDAX).Symbol self.rsi = algorithm.RSI(self.symbol, 14, MovingAverageType.Simple, Resolution.Daily) # Volume times price tells us average daily volume in dollars self.volume = IndicatorExtensions.Times(algorithm.SMA(self.symbol, 30, Resolution.Daily, Field.Volume), algorithm.SMA(self.symbol, 30, Resolution.Daily, Field.Close)) self.minimumVolume = minimumVolumne # Create method the returns true if the instrument is investable (i.e. passes our volume tests) def Investable(self): return (self.volume.Current.Value > self.minimumVolume) # returns true if investable, otherwise false