From 97d285adc6c581a0c9a8ec15cb4390bbc7708471 Mon Sep 17 00:00:00 2001 From: LouisSzeto Date: Fri, 4 Oct 2024 17:27:56 +0800 Subject: [PATCH] Add example of dataless universe --- .../99 Examples.html | 128 +++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/03 Writing Algorithms/12 Universes/11 Dataless Scheduled Universes/99 Examples.html b/03 Writing Algorithms/12 Universes/11 Dataless Scheduled Universes/99 Examples.html index f6310606bd..3a71076592 100644 --- a/03 Writing Algorithms/12 Universes/11 Dataless Scheduled Universes/99 Examples.html +++ b/03 Writing Algorithms/12 Universes/11 Dataless Scheduled Universes/99 Examples.html @@ -1,6 +1,128 @@

The following examples demonstrate some common practices for dataless scheduled universes.

-

Example 1: Quarter End Selection

+

Example 1: Bulk Download Custom List

+

The following example directly download a dataframe file from dropbox, in which its only column contains a list of equity to be included in the universe on that day with the date as index. The dataless scheduled universe can then retrieve the required equities from that day.

+
+
public class DatalessScheduledUniverseExampleAlgorithm : QCAlgorithm
+{
+    // A dictionary of date-stock list pairs for easy access.
+    private Dictionary<DateTime, string> _selections = new();
+    private List<Symbol> _universe = new();
+
+    public override void Initialize()
+    {
+        SetStartDate(2015, 1, 1);
+
+        // To download the list of stocks to be included in the universe of each day, make sure you set "dl=1" for dropbox links.
+        var file = Download("https://www.dropbox.com/scl/fi/fbrxitk4ec3w91nse1raa/df.csv?rlkey=7r042rukzkthp7y1srloyhkov&st=5r4sdfwd&dl=1");
+        // Map into a dictionary of date-stock list pairs for easy access. Remember to skip the header row
+        foreach (var line in file.Split('\n').Skip(1))
+        {
+            // Skip empty line
+            if (line.IsNullOrEmpty())
+            {
+                continue;
+            }
+            
+            // CSV entry items are split by comma.
+            var items = line.Split(',');
+
+            var date = Parse.DateTimeExact(items[0], "yyyy-MM-dd").Date;
+            _selections[date] = String.Join(',', items.Skip(1));
+        }
+
+        // Daily weight signals from our custom universe data only requires daily resolution to trade with.
+        UniverseSettings.Resolution = Resolution.Daily;
+        // Filter using the custom dataset, our sample data is by daily basis.
+        AddUniverse(
+            new ScheduledUniverse(
+                DateRules.EveryDay(),
+                TimeRules.At(8, 0),
+                (dt) => {
+                    // Check if the date is in the selection dictionary with stocks selection, return empty list if not.
+                    if (!_selections.TryGetValue(dt.Date, out var stockListString))
+                    {
+                        return Enumerable.Empty<Symbol>();
+                    }
+
+                    // The stock list is in string format that each stock is split by ",".
+                    _universe = stockListString.Split(',')
+                        // All selections in list are US Equity.
+                        .Select(x => QuantConnect.Symbol.Create(x, SecurityType.Equity, Market.USA))
+                        .ToList();
+                    return _universe;
+            }));
+    }
+
+    public override void OnData(Slice slice)
+    {
+        var universeCount = _universe.Count;
+
+        // Invest equally to evenly dissipate capital risk. Since the resolution is daily, there is no issue for over rebalancing.
+        SetHoldings(_universe.Select(symbol => new PortfolioTarget(symbol, 1m / universeCount)).ToList());
+    }
+
+    public override void OnSecuritiesChanged(SecurityChanges changes)
+    {
+        // Liquidate the remove securities to free margin.
+        foreach (var removed in changes.RemovedSecurities)
+        {
+            Liquidate(removed.Symbol);
+        }
+    }
+}
+
from AlgorithmImports import * 
+from io import StringIO
+
+class DatalessScheduledUniverseExampleAlgorithm(QCAlgorithm):
+    
+    def initialize(self) -> None:
+        self.set_start_date(2015, 1, 1)
+
+        # To download the list of stocks to be included in the universe of each day, make sure you set "dl=1" for dropbox links.
+        file = self.download("https://www.dropbox.com/scl/fi/fbrxitk4ec3w91nse1raa/df.csv?rlkey=7r042rukzkthp7y1srloyhkov&st=5r4sdfwd&dl=1")
+        # Map into a dictionary of date-stock list pairs for easy access.
+        df = pd.read_csv(StringIO(file), index_col=0).iloc[:, 0]
+        df.index = pd.to_datetime(df.index).date
+        self.selections = df.to_dict()
+
+        # Daily weight signals from our custom universe data only requires daily resolution to trade with.
+        self.universe_settings.resolution = Resolution.DAILY
+        # Filter using the custom dataset, our sample data is by daily basis.
+        self.add_universe(
+            ScheduledUniverse(
+                self.date_rules.every_day(), 
+                self.time_rules.at(8, 0), 
+                self._select_symbols
+            ))
+    
+    def _select_symbols(self, dt: datetime) -> List[Symbol]:
+        # Check if the date is in the selection dictionary with stocks selection, return empty list if not.
+        date = dt.date()
+        if date not in self.selections:
+            return []
+        
+        self._universe = [
+            # All selections in list are US Equity.
+            Symbol.create(x, SecurityType.EQUITY, Market.USA)
+            # The stock list is in string format that each stock is split by ","
+            for x in self.selections[date].split(",")
+        ]
+        return self._universe
+
+    def on_data(self, slice: Slice) -> None:
+        # Invest equally to evenly dissipate capital risk. Since the resolution is daily, there is no issue for over rebalancing.
+        self.set_holdings([
+            PortfolioTarget(symbol, 1./len(self._universe)) for symbol in self._universe
+        ])
+
+    def on_securities_changed(self, changes: SecurityChanges) -> None:
+        # Liquidate the remove securities to free margin.
+        for removed in changes.removed_securities:
+            self.liquidate(removed.symbol)
+
+ +

Example 2: Quarter End Selection

The following example selects SPY on the last month of each quarter. For the remaining months, it selects no assets.

public class DatalessScheduledUniverseDemoAlgorithm : QCAlgorithm
@@ -38,7 +160,7 @@ 

Example 1: Quarter End Selection

return []
-

Example 2: Third Week VIX

+

Example 3: Third Week VIX

Standard Options expire at end of the third week of each month. The following algorithm selects VIX-related products on the third week to trade the foreseeable increasing volatility:

public class DatalessScheduledUniverseDemoAlgorithm : QCAlgorithm
@@ -63,7 +185,7 @@ 

Example 2: Third Week VIX

} _month = dt.Month; _week = 0; - return Enumerable.Empty(); + return Enumerable.Empty<Symbol>(); } )); }