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