| Overall Statistics |
|
Total Orders 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Start Equity 100000.0 End Equity 100000 Net Profit 0% Sharpe Ratio 0 Sortino Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -1.46 Tracking Error 0.648 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset Portfolio Turnover 0% |
# region imports
from AlgorithmImports import *
import requests
import json
import time
# endregion
from typing import List
class CoinGeckoUniverse:
def __init__(self, algorithm, categories):
self.algorithm = algorithm
self.categories = categories
def fetch_symbols(self):
all_symbols = []
for category in self.categories:
url = f"https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&category={category}"
retry_attempts = 3
for attempt in range(retry_attempts):
try:
response = self.algorithm.download(url)
if response:
data = json.loads(response)
symbols = [coin['symbol'].upper() + 'USD' for coin in data if 'symbol' in coin]
all_symbols.extend(symbols)
self.algorithm.debug(f"Fetching Symbols Successful")
break
else:
print("Failed to fetch symbols for category:", category)
break
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
self.algorithm.debug(f"Attempt {attempt + 1} failed: {e}")
self.algorithm.sleep(2000) # Wait before retrying (milliseconds)
return all_symbols# region imports
from AlgorithmImports import *
from datetime import timedelta
# endregion
class Criteria(object):
def __init__(self, algorithm, crypto, ema_period, std_period):
self.algorithm = algorithm
self._symbol = crypto.symbol
self._value = self._symbol.value
self._volume_in_usd = crypto.volume_in_usd
self._ema = ExponentialMovingAverage(ema_period)
self._std = StandardDeviation(std_period)
self.ema_value = 0
self.percentage_volatility = 0
self.ema_period = ema_period
self.lookback_period = self.algorithm.look_back
self.criteria_met = False
def update(self, time, crypto_close, crypto_symbol):
if self._ema.update(time, crypto_close) and self._std.update(time, crypto_close):
self.ema_value = self._ema.current.value
self.percentage_volatility = self._std.current.value / crypto_close * 100
self.criteria_met = crypto_close > self.ema_value
def ema_criteria(self, symbol):
# Fetch the historical EMA data
ema_history = self.algorithm.indicator_history(self._ema, symbol, timedelta(days=self.lookback_period))
ema_values = ema_history.data_frame['current']
# Fetch the historical price data
history = self.algorithm.history(symbol, self.lookback_period, Resolution.DAILY)
# Ensure we have enough data
if len(history) < self.lookback_period:
self.algorithm.log(f"Not enough data for {symbol}. History length: {len(history)})")
return False
# Track the index of the last closing price below the EMA
last_below_ema_index = None
# Iterate through historical data to find the last close below EMA
for index in range(len(history) - 1, -1, -1):
close_price = history.iloc[index]['close']
ema_value = ema_values.iloc[index]
if close_price < ema_value:
last_below_ema_index = index
break
# If no closing price below EMA was found, return False
if last_below_ema_index is None:
return False
# Check if any candle after the last_below_ema_index opened and closed above the EMA
for index in range(last_below_ema_index + 1, len(history)):
open_price = history.iloc[index]['open']
close_price = history.iloc[index]['close']
ema_value = ema_values.iloc[index]
if open_price > ema_value and close_price > ema_value:
return True
return False
from AlgorithmImports import *
from CoinGeckoUniverse import CoinGeckoUniverse
from Criteria import Criteria
class UniverseSelectionModel:
def __init__(self, algorithm):
self.algorithm = algorithm
self.categories = ['layer-1', 'depin', 'proof-of-work-pow', 'proof-of-stake-pos', 'meme-token', 'dog-themed-coins',
'eth-2-0-staking', 'non-fungible-tokens-nft', 'governance', 'artificial-intelligence',
'infrastructure', 'layer-2', 'zero-knowledge-zk', 'storage', 'oracle', 'bitcoin-fork',
'restaking', 'rollup', 'metaverse', 'privacy-coins', 'layer-0-l0', 'solana-meme-coins',
'data-availabilit', 'internet-of-things-iot', 'frog-themed-coins', 'ai-agents',
'superchain-ecosystem', 'bitcoin-layer-2', 'bridge-governance-tokens', 'modular-blockchain',
'cat-themed-coins', 'cross-chain-communication', 'analytics', 'identity', 'wallets',
'masternodes']
self.coin_universe = CoinGeckoUniverse(self.algorithm, self.categories)
self.tickers = self.coin_universe.fetch_symbols()
self.count = 10
self.std_period = 20
self.ema_period = 20
self.criteria_by_symbol = {}
def coarse_filters(self, coarse):
for crypto in coarse:
symbol = crypto.symbol
if symbol.value in self.tickers:
if symbol not in self.criteria_by_symbol:
self.criteria_by_symbol[symbol] = Criteria(self.algorithm, crypto, self.ema_period, self.std_period)
self.criteria_by_symbol[symbol].update(crypto.end_time, crypto.close, crypto.symbol)
if self.algorithm.is_warming_up:
return Universe.UNCHANGED
### filter logic using self.criteria_by_symbol
filtered = [x for x in self.criteria_by_symbol.values() if x._volume_in_usd > 10000 and x.criteria_met]
self.algorithm.Debug(f"First Symbol in Coarse Filtered: {filtered[0]._volume_in_usd if filtered else 'None'}")
filtered.sort(key=lambda x: x.percentage_volatility, reverse=True)
self.algorithm.Debug(f"Sorting Successful: {filtered[0]._value if filtered else 'None'}")
for x in filtered[:self.count]:
self.algorithm.debug('symbol: ' + str(x._value) + ' Volume: ' + str(x._volume_in_usd) + "$")
self.algorithm.Debug(f"Length of criteria_by_symbol: {len(self.criteria_by_symbol)}")
### return symbols in self.criteria_by_symbol.keys() that pass the filter
return [f._symbol for f in filtered]
from AlgorithmImports import *
from CryptoUniverseSelection import UniverseSelectionModel
class CryptoTradingAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2020, 1, 1)
self.set_brokerage_model(BrokerageName.KRAKEN, AccountType.CASH)
self.btcusd = self.add_crypto("BTCUSD", Resolution.HOUR, Market.KRAKEN).symbol
self.set_benchmark("BTCUSD")
self.look_back = 35
self.set_warm_up(self.look_back, Resolution.DAILY)
# Create an instance of the universe selection model
self.universe_model = UniverseSelectionModel(self)
# Define the universe
# Add Kraken universe with a selection function
self.add_universe(CryptoUniverse.kraken(self.universe_model.coarse_filters))
self.alpha_counter = 2
# self.schedule.on(self.date_rules.month_start("SPY"),
# self.time_rules.midnight,
# self.add_universe(CryptoUniverse.kraken(self.universe_model.coarse_filters)))
def OnData(self, data):
# for symbol in self.Securities.Keys:
# self.SetHoldings(symbol, 0.01)
pass