| Overall Statistics |
|
Total Trades 156 Average Win 14.99% Average Loss -1.97% Compounding Annual Return 539.329% Drawdown 28.100% Expectancy 3.081 Net Profit 4117.780% Sharpe Ratio 5.675 Probabilistic Sharpe Ratio 99.824% Loss Rate 53% Win Rate 47% Profit-Loss Ratio 7.60 Alpha 2.673 Beta 0.408 Annual Standard Deviation 0.565 Annual Variance 0.319 Information Ratio 3.034 Tracking Error 0.626 Treynor Ratio 7.86 Total Fees $70222.49 Estimated Strategy Capacity $1000000.00 Lowest Capacity Asset SOLUSDT 18N |
from datetime import timedelta
from AlgorithmImports import *
import math
# from Shared.IntradayMomentumIndex importIn
from SmartRollingWindow import *
def truncate(number, decimals=0):
"""
Returns a value truncated to a specific number of decimal places.
"""
if not isinstance(decimals, int):
raise TypeError("decimal places must be an integer.")
elif decimals < 0:
raise ValueError("decimal places has to be 0 or more.")
elif decimals == 0:
return math.trunc(number)
factor = 10.0 ** decimals
return math.trunc(number * factor) / factor
class Asset():
def __init__(self, algorithm, symbol):
self.symbol = symbol
self.algorithm = algorithm
def InitIndicators(self, slowPeriod, fastPeriod, resolution):
self.fast = self.algorithm.EMA(self.symbol, fastPeriod, Resolution.Daily)
self.slow = self.algorithm.EMA(self.symbol, slowPeriod, Resolution.Daily)
self.slowWindow = SmartRollingWindow('float', 2)
self.fastWindow = SmartRollingWindow('float', 2)
self.priceWindow = SmartRollingWindow('float', 2)
def UpdateIndicators(self):
self.slowWindow.Add(self.slow.Current.Value)
self.fastWindow.Add(self.fast.Current.Value)
self.priceWindow.Add(self.algorithm.Securities[self.symbol].Price)
def PrefixWithSymbol(self, str):
return "{}: {}".format(self.symbol.Value, str)
def Plot(self, chartName):
self.algorithm.Plot(chartName, self.PrefixWithSymbol("Price"), self.algorithm.Securities[self.symbol].Price)
self.algorithm.Plot(chartName, self.PrefixWithSymbol("Slow"), self.slow.Current.Value)
self.algorithm.Plot(chartName, self.PrefixWithSymbol("Fast"), self.fast.Current.Value)
class FocusedYellowGreenJellyfish(QCAlgorithm):
def Initialize(self):
self.InitAlgoParams()
self.InitBacktestParams()
self.InitAssets()
self.InitIndicators()
def InitAlgoParams(self):
self.benchmarkTicker = 'BTCUSDT';
self.tickers = ["SOLUSDT", "ETHUSDT", "BNBUSDT"]
self.assets = {}
self.ticker = "SOLUSDT"
self.resolution = Resolution.Minute
self.slowPeriod = int(self.GetParameter('slowPeriod'))
self.fastPeriod = int(self.GetParameter('fastPeriod'))
def InitBacktestParams(self):
self.SetAccountCurrency("USDT")
self.SetCash(100000)
self.SetStartDate(2020, 1, 1)
def InitAssets(self):
self.SetBrokerageModel(BrokerageName.Binance, AccountType.Cash)
self.benchmarkSymbol = self.AddCrypto(self.benchmarkTicker, self.resolution).Symbol
for ticker in self.tickers:
symbol = self.AddCrypto(ticker, self.resolution).Symbol
self.assets[ticker] = Asset(self, symbol)
self.SetBenchmark(self.benchmarkTicker)
def InitIndicators(self):
self.SetWarmUp(self.slowPeriod * 2, self.resolution)
for asset in self.assets.values():
asset.InitIndicators(self.slowPeriod, self.fastPeriod, self.resolution)
self.Consolidate(self.benchmarkSymbol, Resolution.Daily, self.OnConsolidatedBarClose)
def UpdateRollingWindows(self):
for asset in self.assets.values():
asset.UpdateIndicators()
def ShouldExit(self, asset):
return asset.priceWindow.isBelow(asset.slowWindow) or asset.slowWindow.isAbove(asset.fastWindow)
def ShouldEnter(self, asset):
return asset.fastWindow.isAbove(asset.slowWindow) and asset.priceWindow.isAbove(asset.fastWindow)
def OnEndOfDay(self):
self.PlotCharts()
self.UpdateRollingWindows()
def OnConsolidatedBarClose(self, bar):
for asset in self.assets.values():
if not asset.slowWindow.IsReady():
return
if self.Portfolio[asset.symbol].Invested and self.ShouldExit(asset):
self.Liquidate(asset.symbol)
elif not self.Portfolio[asset.symbol].Invested and self.ShouldEnter(asset):
percent = truncate(1 / len(self.assets.values()), 1)
cost = self.Portfolio.TotalPortfolioValue * percent
cash = self.Portfolio.TotalPortfolioValue - self.Portfolio.TotalHoldingsValue
self.Log("Cost: {}, Cash: {}".format(cost, cash))
if (cost > cash):
percent = truncate(cash / self.Portfolio.TotalPortfolioValue, 1)
self.SetHoldings(asset.symbol, percent);
def PlotCharts(self):
chartName = "Charts"
# self.Plot('Benchmark', "Benchmark", self.Securities[self.benchmarkSymbol].Price)
for asset in self.assets.values():
asset.Plot(chartName)