Overall Statistics |
Total Orders 96 Average Win 0.03% Average Loss -0.06% Compounding Annual Return 9.287% Drawdown 18.400% Expectancy -0.253 Start Equity 100000 End Equity 109304.95 Net Profit 9.305% Sharpe Ratio 0.484 Sortino Ratio 0.449 Probabilistic Sharpe Ratio 28.112% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 0.42 Alpha -0.013 Beta 0.501 Annual Standard Deviation 0.139 Annual Variance 0.019 Information Ratio -0.677 Tracking Error 0.139 Treynor Ratio 0.135 Total Fees $96.00 Estimated Strategy Capacity $140000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 0.27% |
from AlgorithmImports import * class TwoTimeframesSameAsset(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 1, 1) self.SetEndDate(2021, 1, 1) self.SetCash(100000) self.spy = self.AddEquity("SPY", Resolution.Hour) self.spy.SetDataNormalizationMode(DataNormalizationMode.Raw) self.SetUniverseSelection(ManualUniverseSelectionModel(["SPY"])) self.SetAlpha(CompositeAlphaModel( HourlyStrategy(), DailyStrategy() )) self.SetPortfolioConstruction(CustomPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) self.SetRiskManagement(NullRiskManagementModel()) def OnData(self, data): self.Log(f"OnData called at {self.Time}: Data type: {data.GetType().Name}") class HourlyStrategy(AlphaModel): def __init__(self): self.last_hour = None self.Name = "HourlyStrategy" def Update(self, algorithm: QCAlgorithm, data: Slice) -> List[Insight]: if not data.ContainsKey("SPY"): return [] current_hour = algorithm.Time.hour if self.last_hour == current_hour: return [] self.last_hour = current_hour spy_data = data["SPY"] if spy_data is None or spy_data.Price == 0: return [] price = spy_data.Price insight = Insight.Price("SPY", timedelta(hours=1), InsightDirection.Up if current_hour % 2 == 0 else InsightDirection.Down, sourceModel=self.Name) algorithm.Log(f"Hourly Strategy: Generated {'Up' if current_hour % 2 == 0 else 'Down'} insight at {algorithm.Time}. Price: {price}") return [insight] class DailyStrategy(AlphaModel): def __init__(self): self.last_date = None self.Name = "DailyStrategy" def Update(self, algorithm: QCAlgorithm, data: Slice) -> List[Insight]: if not data.ContainsKey("SPY"): return [] current_date = algorithm.Time.date() if self.last_date == current_date: return [] self.last_date = current_date spy_data = data["SPY"] if spy_data is None or spy_data.Price == 0: return [] price = spy_data.Price insight = Insight.Price("SPY", timedelta(days=1), InsightDirection.Up if current_date.day % 2 == 0 else InsightDirection.Down, sourceModel=self.Name) algorithm.Log(f"Daily Strategy: Generated {'Up' if current_date.day % 2 == 0 else 'Down'} insight at {algorithm.Time}. Price: {price}") return [insight] class CustomPortfolioConstructionModel(PortfolioConstructionModel): def __init__(self): self.hourly_allocation = 50000 self.daily_allocation = 50000 self.last_rebalance = datetime.min self.rebalance_time = timedelta(days=1) # Rebalance daily def CreateTargets(self, algorithm, insights): if len(insights) == 0: return [] current_time = algorithm.Time if (current_time - self.last_rebalance) < self.rebalance_time: return [] self.last_rebalance = current_time # Update allocations based on current portfolio value total_portfolio_value = max(0, algorithm.Portfolio.TotalPortfolioValue) if self.hourly_allocation + self.daily_allocation > 0: hourly_value = self.hourly_allocation / (self.hourly_allocation + self.daily_allocation) * total_portfolio_value daily_value = self.daily_allocation / (self.hourly_allocation + self.daily_allocation) * total_portfolio_value else: hourly_value = daily_value = total_portfolio_value / 2 self.hourly_allocation = hourly_value self.daily_allocation = daily_value hourly_insights = [x for x in insights if x.SourceModel == "HourlyStrategy"] daily_insights = [x for x in insights if x.SourceModel == "DailyStrategy"] targets = [] spy_price = algorithm.Securities["SPY"].Price if spy_price > 0: if hourly_insights and len(hourly_insights) > 0: hourly_direction = hourly_insights[0].Direction hourly_target = PortfolioTarget("SPY", self.hourly_allocation / spy_price * (1 if hourly_direction == InsightDirection.Up else -1)) targets.append(hourly_target) if daily_insights and len(daily_insights) > 0: daily_direction = daily_insights[0].Direction daily_target = PortfolioTarget("SPY", self.daily_allocation / spy_price * (1 if daily_direction == InsightDirection.Up else -1)) targets.append(daily_target) algorithm.Log(f"Rebalancing at {current_time}. Hourly allocation: ${self.hourly_allocation:.2f}, Daily allocation: ${self.daily_allocation:.2f}") return targets def OnSecuritiesChanged(self, algorithm, changes): pass