Overall Statistics |
Total Trades 77 Average Win 0.15% Average Loss -0.51% Compounding Annual Return -12.735% Drawdown 24.800% Expectancy -0.486 Net Profit -3.116% Sharpe Ratio 0.216 Probabilistic Sharpe Ratio 32.308% Loss Rate 60% Win Rate 40% Profit-Loss Ratio 0.29 Alpha 0 Beta 0 Annual Standard Deviation 0.683 Annual Variance 0.466 Information Ratio 0.216 Tracking Error 0.683 Treynor Ratio 0 Total Fees BUSD510.37 Estimated Strategy Capacity BUSD5200000.00 Lowest Capacity Asset ETHBUSD 18N |
#region imports from AlgorithmImports import * from QuantConnect.Indicators import * #endregion class MyAlphaModelDown(AlphaModel): def __init__(self, mainAlgo): self.algo = mainAlgo def Update(self, algorithm, data): insights = [] # always emit Down Insight insights.append((Insight.Price(self.algo.eth, Expiry.EndOfDay, InsightDirection.Down))) self.rebalanceTime = Expiry.EndOfDay(algorithm.Time) return insights def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' pass
#region imports from AlgorithmImports import * from QuantConnect.Indicators import * #endregion class MyAlphaModelUp(AlphaModel): def __init__(self, mainAlgo): self.algo = mainAlgo def Update(self, algorithm, data): insights = [] # always emit Up Insight insights.append((Insight.Price(self.algo.eth, Expiry.EndOfDay, InsightDirection.Up))) self.rebalanceTime = Expiry.EndOfDay(algorithm.Time) return insights def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' pass
#region imports from AlgorithmImports import * import datetime #endregion class MyExecutionModel(ExecutionModel): def __init__(self, mainAlgo): '''Initializes a new instance of the MyExecutionModel class''' self.targetsCollection = PortfolioTargetCollection() self.minOrderSizeInUSD = 10 self.algo = mainAlgo # Fill the supplied portfolio targets efficiently def Execute(self, algorithm, targets: List[PortfolioTarget]) -> None: '''Immediately submits orders for the specified portfolio targets. Args: algorithm: The algorithm instance targets: The portfolio targets to be ordered''' # for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call self.targetsCollection.AddRange(targets) if not self.targetsCollection.IsEmpty: for target in self.targetsCollection.OrderByMarginImpact(algorithm): security = algorithm.Securities[target.Symbol] # calculate remaining quantity to be ordered quantity = OrderSizing.GetUnorderedQuantity(algorithm, target, security) if quantity != 0: # Helper method to determine if the requested quantity is above the algorithm minimum order margin portfolio percentage aboveMinimumPortfolio = BuyingPowerModelExtensions.AboveMinimumOrderMarginPortfolioPercentage(security.BuyingPowerModel, security, quantity, algorithm.Portfolio, algorithm.Settings.MinimumOrderMarginPortfolioPercentage) if aboveMinimumPortfolio: # expiryDatetime = self.algo.Time + timedelta(hours=6) # expiryStringTag = "expires: " + expiryDatetime.strftime("%m/%d/%Y, %H:%M:%S") + "CB: " + str(self.algo.Portfolio.CashBook["BUSD"].ValueInAccountCurrency) # order_properties = OrderProperties() # order_properties.TimeInForce = TimeInForce.GoodTilDate(expiryDatetime) # algorithm.MarketOrder(security, quantity, tag=expiryStringTag, orderProperties=order_properties) algorithm.MarketOrder(security, quantity) # leading to lingering small orders - issue? # self.targetsCollection.ClearFulfilled(algorithm) self.targetsCollection.Clear() # print all CashBook Positions after trading # for cash in self.algo.Portfolio.CashBook.Values: # self.algo.Log(f"Holding {cash.Amount} of {cash.Symbol} ({cash.ValueInAccountCurrency} BUSD value)") # Optional: Securities changes event for handling new securities. def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None: # Security additions and removals are pushed here. # This can be used for setting up algorithm state. # changes.AddedSecurities # changes.RemovedSecurities pass
#region imports from AlgorithmImports import * import datetime #endregion # https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/portfolio-construction/key-concepts # Portfolio construction scaffolding class; basic method args. class MyPortfolioConstructionModel(PortfolioConstructionModel): def __init__(self, rebalance, mainAlgo): '''Initialize a new instance of MyPortfolioConstructionModel Args: rebalance: Rebalancing parameter. If it is a timedelta, date rules or Resolution, it will be converted into a function. If None will be ignored. The function returns the next expected rebalance time for a given algorithm UTC DateTime. The function returns null if unknown, in which case the function will be called again in the next loop. Returning current time will trigger rebalance. portfolioBias: Specifies the bias of the portfolio (Short, Long/Short, Long)''' super().__init__() self.algo = mainAlgo self.portfolioBias = PortfolioBias.LongShort # If the argument is an instance of Resolution or Timedelta # Redefine rebalancingFunc rebalancingFunc = rebalance if isinstance(rebalance, int): rebalance = Extensions.ToTimeSpan(rebalance) if isinstance(rebalance, timedelta): rebalancingFunc = lambda dt: dt + rebalance if rebalancingFunc: self.SetRebalancingFunc(rebalancingFunc) # REQUIRED: Will determine the target percent for each insight def DetermineTargetPercent(self, activeInsights): '''Will determine the target percent for each insight Args: activeInsights: The active insights to generate a target for''' result = {} # give equal weighting to each security count = sum(x.Direction != InsightDirection.Flat and self.RespectPortfolioBias(x) for x in activeInsights) percent = 0 if count == 0 else 1.0 / count for insight in activeInsights: # return insight only when all active insights have the same direction if all(insight.Direction == other_insights.Direction for other_insights in activeInsights): result[insight] = (insight.Direction if self.RespectPortfolioBias(insight) else InsightDirection.Flat) * percent else: result[insight] = (InsightDirection.Flat) * percent return result # Determines if the portfolio should be rebalanced base on the provided rebalancing func def IsRebalanceDue(self, insights: List[Insight], algorithmUtc: datetime) -> bool: return True def RespectPortfolioBias(self, insight): '''Method that will determine if a given insight respects the portfolio bias Args: insight: The insight to create a target for ''' return self.portfolioBias == PortfolioBias.LongShort or insight.Direction == self.portfolioBias # OPTIONAL: Security change details def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None: pass
# region imports from AlgorithmImports import * from AlphaModelUp import * from AlphaModelDown import * from ExecutionModel import * from PortfolioConstructionModel import * # endregion class FocusedBrownJaguar(QCAlgorithm): def Initialize(self): # *** initial configurations and backtest *** self.SetStartDate(2022, 9, 30) # Set Start Date self.SetEndDate(2022, 12, 22) # Set End Date self.SetSecurityInitializer(self.CustomSecurityInitializer) self.SetAccountCurrency("BUSD") # Set Account Currency self.SetCash("BUSD", 100000, 1) # Set Strategy Cash self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(CryptoCoarseFundamentalUniverse(Market.Binance, self.UniverseSettings, self.universe_filter)) self.SetBenchmark(Symbol.Create("BTCUSDC", SecurityType.Crypto, Market.Binance)) self.ethSecurity = self.AddCrypto("ETHBUSD", Resolution.Daily, market=Market.Binance) self.eth = self.ethSecurity.Symbol # *** Framework initialization *** self.AddAlpha(MyAlphaModelUp(self)) self.AddAlpha(MyAlphaModelDown(self)) self.SetPortfolioConstruction(MyPortfolioConstructionModel(self.DateRules.EveryDay(), self)) self.AddRiskManagement(NullRiskManagementModel()) self.SetExecution(ImmediateExecutionModel()) # *** Brokerage settings self.SetBrokerageModel(BrokerageName.Binance, AccountType.Margin) self.order_properties = BinanceOrderProperties() def OnData(self, data): pass def OnSecuritiesChanged(self, changes: SecurityChanges) -> None: pass def CustomSecurityInitializer(self, security): security.SetFeeModel(BinanceFeeModel()) security.SetFillModel(ImmediateFillModel()) security.SetBuyingPowerModel(SecurityMarginModel(1)) def universe_filter(self, crypto_coarse: List[CryptoCoarseFundamental]) -> List[Symbol]: # for demonstration purposes, return only Ethereum static_universe_list = [self.eth] return static_universe_list