Overall Statistics
Total Orders
1162
Average Win
0.01%
Average Loss
-0.01%
Compounding Annual Return
-32.963%
Drawdown
3.200%
Expectancy
-0.545
Start Equity
100000
End Equity
96806.19
Net Profit
-3.194%
Sharpe Ratio
-5.165
Sortino Ratio
-6.873
Probabilistic Sharpe Ratio
1.737%
Loss Rate
76%
Win Rate
24%
Profit-Loss Ratio
0.88
Alpha
-0.213
Beta
0.372
Annual Standard Deviation
0.058
Annual Variance
0.003
Information Ratio
-0.882
Tracking Error
0.075
Treynor Ratio
-0.805
Total Fees
$1162.00
Estimated Strategy Capacity
$250000000.00
Lowest Capacity Asset
AMS R735QTJ8XC9X
Portfolio Turnover
7.21%
Drawdown Recovery
0
# region imports
from AlgorithmImports import *
# endregion


class PredictionUniverseAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2026, 2, 10) # Set this 1 day before the dataset begins.
        self.set_cash(100_000)
        self.settings.seed_initial_prices = True
        # Define some parameters.
        self._return_prediction_threshold = 0
        # Add the universe of custom data.
        self.universe_settings.resolution = Resolution.DAILY
        self._universe = self.add_universe(PredictionUniverse, self._select_assets)
        # Add a Scheduled Event to rebalance the portfolio every day.
        self.schedule.on(self.date_rules.every_day('SPY'), self.time_rules.at(8, 0), self._rebalance)

    def _select_assets(self, data):
        # Select the assets with a return prediction above some threshold.
        return [stock.symbol for stock in data if stock.value > self._return_prediction_threshold]
    
    def _rebalance(self):
        # Form an equal-weighted portfolio with the assets in the universe.
        symbols = self._universe.selected
        if not symbols:
            return
        targets = [PortfolioTarget(symbol, 1/len(symbols)) for symbol in symbols]
        self.set_holdings(targets, True)


# Define a custom universe class that reads from the JSON file
# we created in the research notebook.
class PredictionUniverse(PythonData):

    def get_source(self, config, date, is_live_mode):
        # Read from the JSON file we saved in the Object Store.
        return SubscriptionDataSource(
            'research-to-backtest-factors.json', 
            SubscriptionTransportMedium.OBJECT_STORE, 
            FileFormat.UNFOLDING_COLLECTION
        )

    def reader(self, config, line, date, is_live):
        objects = []
        # Iterate through each day.
        for obj in json.loads(line):
            end_time = datetime.strptime(obj["date"], "%Y-%m-%d")
            # Iterate through each stock on this day.
            for symbol, prediction in obj['prediction_by_symbol'].items():
                stock = PredictionUniverse()
                stock.symbol = Symbol(SecurityIdentifier.parse(symbol), "")
                stock.end_time = end_time
                stock.value = prediction
                objects.append(stock)
        # The BaseDataCollection contains multiple PredictionUniverse objects
        # for each day. Set its `time` to match the `end_time` of one of the objects.
        # We pack the collection and timestamp it with the last timestamp (-1) to signal 
        # that the collection has data prior to (or including) that timestamp.
        return BaseDataCollection(objects[-1].end_time, config.symbol, objects)