From 942978b7adb6fc10a9f4f239d7017624955ef34e Mon Sep 17 00:00:00 2001 From: Alexandre Catarino Date: Tue, 17 Mar 2026 19:31:03 +0000 Subject: [PATCH 1/6] Add examples for all HuggingFace models (#2102) Add documentation sections with algorithm examples for all HuggingFace models in the popular models table that were missing examples: - Sentiment Analysis: covers 8 text classification models - Fill-Mask: covers BERT, DistilBERT, RoBERTa, DeBERTa - Text Generation: covers GPT-2, Gemma, DeepSeek - Moirai: time series forecasting (small/base/large) - MOMENT: time series foundation model - Granite TTM: IBM lightweight time series forecasting - Chronos-Bolt: efficient Chronos variant Update the model table to link every model to its example page. Fix AventIQ-AI model category from Time Series Forecasting to Text Classification. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../04 Hugging Face/02 Popular Models/00.json | 9 +- .../01 Introduction.html | 14 ++ .../06 Sentiment Analysis/99 Examples.html | 112 ++++++++++++ .../06 Sentiment Analysis/metadata.json | 12 ++ .../07 Fill-Mask/01 Introduction.html | 10 ++ .../07 Fill-Mask/99 Examples.html | 129 ++++++++++++++ .../07 Fill-Mask/metadata.json | 12 ++ .../08 Text Generation/01 Introduction.html | 9 + .../08 Text Generation/99 Examples.html | 119 +++++++++++++ .../08 Text Generation/metadata.json | 12 ++ .../09 Moirai/01 Introduction.html | 16 ++ .../09 Moirai/99 Examples.html | 160 ++++++++++++++++++ .../02 Popular Models/09 Moirai/metadata.json | 12 ++ .../10 MOMENT/01 Introduction.html | 9 + .../10 MOMENT/99 Examples.html | 119 +++++++++++++ .../02 Popular Models/10 MOMENT/metadata.json | 12 ++ .../11 Granite TTM/01 Introduction.html | 9 + .../11 Granite TTM/99 Examples.html | 132 +++++++++++++++ .../11 Granite TTM/metadata.json | 12 ++ .../12 Chronos-Bolt/01 Introduction.html | 10 ++ .../12 Chronos-Bolt/99 Examples.html | 147 ++++++++++++++++ .../12 Chronos-Bolt/metadata.json | 12 ++ .../machine-learning/hugging-face-table.html | 44 ++--- 23 files changed, 1109 insertions(+), 23 deletions(-) create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/01 Introduction.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/metadata.json create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/01 Introduction.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/metadata.json create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/01 Introduction.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/metadata.json create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/01 Introduction.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html create mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/metadata.json diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json index 2a337d7966..13b8b3714b 100644 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json @@ -7,6 +7,13 @@ "featureShortDescription": { "03" : "Time series forecasting", "04" : "Question Answering", - "05" : "Sentiment analysis" + "05" : "Sentiment analysis", + "06" : "Text classification", + "07" : "Feature extraction", + "08" : "Text generation", + "09" : "Time series forecasting", + "10" : "Time series forecasting", + "11" : "Time series forecasting", + "12" : "Time series forecasting" } } \ No newline at end of file diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/01 Introduction.html new file mode 100644 index 0000000000..12f5a7c2f5 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/01 Introduction.html @@ -0,0 +1,14 @@ +

This page explains how to use Hugging Face sentiment analysis models in LEAN trading algorithms. These models classify financial text into sentiment categories like positive, negative, and neutral. The following models are available:

+ + + +

All of these models accept text input and return classification labels with confidence scores. You can use them with the Hugging Face transformers library to analyze the sentiment of financial news and social media posts, then use the results to inform trading decisions.

diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html new file mode 100644 index 0000000000..3333aad922 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html @@ -0,0 +1,112 @@ +

+ The following examples demonstrate usage of Hugging Face sentiment analysis models. +

+

+ Example 1: News Sentiment Trading +

+

+ The following algorithm selects the most volatile asset at the beginning of each month. + It gets the Tiingo News articles that were released for the asset over the previous 10 days and then feeds them into a sentiment analysis model. + It aggregates the sentiment scores of all the news releases. + If the aggregated sentiment is positive, it enters a long position for the month. + If it's negative, it enters a short position. + You can replace the model name with any of the sentiment analysis models listed on the introduction page. +

+
+
from transformers import pipeline, set_seed
+
+class SentimentAnalysisModelAlgorithm(QCAlgorithm):
+
+    def initialize(self):
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(100_000)
+
+        self.universe_settings.resolution = Resolution.DAILY
+        self.universe_settings.schedule.on(self.date_rules.month_start("SPY"))
+        self._universe = self.add_universe(
+            lambda fundamental: [
+                self.history(
+                    [f.symbol for f in sorted(
+                        fundamental, key=lambda f: f.dollar_volume
+                    )[-10:]],
+                    timedelta(365), Resolution.DAILY
+                )['close'].unstack(0).pct_change().iloc[1:].std().idxmax()
+            ]
+        )
+
+        set_seed(1, True)
+
+        # Load the sentiment analysis pipeline.
+        # Replace the model name with any supported sentiment model.
+        self._sentiment_pipeline = pipeline(
+            "text-classification",
+            model="mrm8488/distilroberta-finetuned-financial-news-sentiment-analysis"
+        )
+
+        self._last_rebalance_time = datetime.min
+        self.set_warm_up(30, Resolution.DAILY)
+
+    def on_warmup_finished(self):
+        self._trade()
+        self.schedule.on(
+            self.date_rules.month_start("SPY", 1),
+            self.time_rules.midnight,
+            self._trade
+        )
+
+    def on_securities_changed(self, changes):
+        for security in changes.removed_securities:
+            self.remove_security(security.dataset_symbol)
+        for security in changes.added_securities:
+            security.dataset_symbol = self.add_data(
+                TiingoNews, security.symbol
+            ).symbol
+
+    def _trade(self):
+        if (self.is_warming_up or
+            self.time - self._last_rebalance_time < timedelta(14)):
+            return
+
+        # Get the target security.
+        security = self.securities[list(self._universe.selected)[0]]
+
+        # Get the latest news articles.
+        articles = self.history[TiingoNews](
+            security.dataset_symbol, 10, Resolution.DAILY
+        )
+        article_text = [
+            article.description for article in articles
+            if article.description
+        ]
+        if not article_text:
+            return
+
+        # Run sentiment analysis on each article.
+        # Truncate long articles to the model's max length.
+        results = self._sentiment_pipeline(
+            article_text, truncation=True, max_length=512
+        )
+
+        # Aggregate sentiment scores.
+        positive_score = 0
+        negative_score = 0
+        for result in results:
+            label = result['label'].lower()
+            score = result['score']
+            if 'pos' in label:
+                positive_score += score
+            elif 'neg' in label:
+                negative_score += score
+
+        self.plot("Sentiment", "Positive", positive_score)
+        self.plot("Sentiment", "Negative", negative_score)
+
+        # Rebalance based on sentiment.
+        weight = 1 if positive_score > negative_score else -0.25
+        self.set_holdings(
+            security.symbol, weight,
+            liquidate_existing_holdings=True
+        )
+        self._last_rebalance_time = self.time
+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/metadata.json new file mode 100644 index 0000000000..58140d6fce --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "This page explains how to use Hugging Face sentiment analysis models in LEAN trading algorithms.", + "keywords": "sentiment analysis model, text classification, pre-trained AI model, financial sentiment, free AI models", + "og:description": "This page explains how to use Hugging Face sentiment analysis models in LEAN trading algorithms.", + "og:title": "Sentiment Analysis Models - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Sentiment Analysis Models - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis.png" + } +} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/01 Introduction.html new file mode 100644 index 0000000000..40d4912ce0 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/01 Introduction.html @@ -0,0 +1,10 @@ +

This page explains how to use Hugging Face fill-mask models in LEAN trading algorithms. Fill-mask models predict the most likely word to fill a masked position in a sentence. You can use them to extract text embeddings and build feature vectors from financial text. The following models are available:

+ + + +

These models are useful for extracting text embeddings from financial news. You can feed these embeddings into a downstream classifier or use cosine similarity to measure the semantic similarity between documents.

diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html new file mode 100644 index 0000000000..397aa20f02 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html @@ -0,0 +1,129 @@ +

+ The following examples demonstrate usage of Hugging Face fill-mask models for feature extraction. +

+

+ Example 1: Embedding-Based News Similarity +

+

+ The following algorithm selects a volatile asset at the beginning of each month. + It uses a fill-mask model to extract embeddings from Tiingo News articles. + It then compares the average embedding of recent news to a reference "bullish" and "bearish" embedding. + If the recent news is more similar to the bullish reference, it enters a long position. + You can replace the model name with any of the fill-mask models listed on the introduction page. +

+
+
import torch
+import numpy as np
+from transformers import AutoTokenizer, AutoModel, set_seed
+
+class FillMaskEmbeddingAlgorithm(QCAlgorithm):
+
+    def initialize(self):
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(100_000)
+
+        self.universe_settings.resolution = Resolution.DAILY
+        self.universe_settings.schedule.on(self.date_rules.month_start("SPY"))
+        self._universe = self.add_universe(
+            lambda fundamental: [
+                self.history(
+                    [f.symbol for f in sorted(
+                        fundamental, key=lambda f: f.dollar_volume
+                    )[-10:]],
+                    timedelta(365), Resolution.DAILY
+                )['close'].unstack(0).pct_change().iloc[1:].std().idxmax()
+            ]
+        )
+
+        set_seed(1, True)
+
+        # Load the model and tokenizer.
+        # Replace with any fill-mask model (e.g., google-bert/bert-base-uncased).
+        model_name = "distilbert/distilbert-base-uncased"
+        self._tokenizer = AutoTokenizer.from_pretrained(model_name)
+        self._model = AutoModel.from_pretrained(model_name)
+        self._model.eval()
+
+        # Create reference embeddings for bullish/bearish text.
+        self._bullish_embedding = self._get_embedding(
+            "Stock prices surged on strong earnings and revenue growth."
+        )
+        self._bearish_embedding = self._get_embedding(
+            "Stock prices plunged on weak earnings and declining revenue."
+        )
+
+        self._last_rebalance_time = datetime.min
+        self.set_warm_up(30, Resolution.DAILY)
+
+    def on_warmup_finished(self):
+        self._trade()
+        self.schedule.on(
+            self.date_rules.month_start("SPY", 1),
+            self.time_rules.midnight,
+            self._trade
+        )
+
+    def on_securities_changed(self, changes):
+        for security in changes.removed_securities:
+            self.remove_security(security.dataset_symbol)
+        for security in changes.added_securities:
+            security.dataset_symbol = self.add_data(
+                TiingoNews, security.symbol
+            ).symbol
+
+    def _get_embedding(self, text):
+        """Extract the [CLS] token embedding from the model."""
+        inputs = self._tokenizer(
+            text, return_tensors="pt", truncation=True, max_length=512
+        )
+        with torch.no_grad():
+            outputs = self._model(**inputs)
+        # Use the [CLS] token (first token) embedding.
+        return outputs.last_hidden_state[:, 0, :].squeeze().numpy()
+
+    def _cosine_similarity(self, a, b):
+        return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
+
+    def _trade(self):
+        if (self.is_warming_up or
+            self.time - self._last_rebalance_time < timedelta(14)):
+            return
+
+        # Get the target security.
+        security = self.securities[list(self._universe.selected)[0]]
+
+        # Get the latest news articles.
+        articles = self.history[TiingoNews](
+            security.dataset_symbol, 10, Resolution.DAILY
+        )
+        article_text = [
+            article.description for article in articles
+            if article.description
+        ]
+        if not article_text:
+            return
+
+        # Get embeddings for each article and average them.
+        embeddings = [self._get_embedding(text) for text in article_text]
+        avg_embedding = np.mean(embeddings, axis=0)
+
+        # Compare to reference embeddings.
+        bullish_sim = self._cosine_similarity(
+            avg_embedding, self._bullish_embedding
+        )
+        bearish_sim = self._cosine_similarity(
+            avg_embedding, self._bearish_embedding
+        )
+
+        self.plot("Similarity", "Bullish", bullish_sim)
+        self.plot("Similarity", "Bearish", bearish_sim)
+
+        # Rebalance based on similarity.
+        weight = 1 if bullish_sim > bearish_sim else -0.25
+        self.set_holdings(
+            security.symbol, weight,
+            liquidate_existing_holdings=True
+        )
+        self._last_rebalance_time = self.time
+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/metadata.json new file mode 100644 index 0000000000..fd584e3045 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "This page explains how to use Hugging Face fill-mask models in LEAN trading algorithms.", + "keywords": "fill-mask model, feature extraction, pre-trained AI model, embeddings, free AI models", + "og:description": "This page explains how to use Hugging Face fill-mask models in LEAN trading algorithms.", + "og:title": "Fill-Mask Models - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Fill-Mask Models - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/fill-mask.png" + } +} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/01 Introduction.html new file mode 100644 index 0000000000..e5da086b71 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/01 Introduction.html @@ -0,0 +1,9 @@ +

This page explains how to use Hugging Face text generation models in LEAN trading algorithms. These models generate text given an input prompt, which you can use for tasks like summarizing financial data or generating structured analysis. The following models are available:

+ + + +

Text generation models can analyze market context and generate structured outputs. You can prompt them to classify market conditions or extract trading signals from financial text. Note that larger models like Gemma-7B and DeepSeek-70B require GPU nodes with sufficient memory.

diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html new file mode 100644 index 0000000000..9200f94168 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html @@ -0,0 +1,119 @@ +

+ The following examples demonstrate usage of Hugging Face text generation models. +

+

+ Example 1: GPT-2 Market Condition Classifier +

+

+ The following algorithm uses GPT-2 to classify market conditions based on recent price data. + At the beginning of each month, it calculates trailing returns, volatility, and momentum for the universe of the 5 most liquid assets. + It then prompts GPT-2 to complete a structured market analysis template and parses the generated text to determine position sizing. +

+
+
from transformers import pipeline, set_seed
+
+class GPT2MarketAnalysisAlgorithm(QCAlgorithm):
+
+    def initialize(self):
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(100_000)
+
+        self.settings.min_absolute_portfolio_target_percentage = 0
+
+        set_seed(1, True)
+
+        # Load the text generation pipeline with GPT-2.
+        self._generator = pipeline(
+            "text-generation",
+            model="openai-community/gpt2"
+        )
+
+        # Define the universe.
+        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
+        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
+        self.universe_settings.resolution = Resolution.DAILY
+        self._universe = self.add_universe(
+            self.universe.top(
+                self.get_parameter('universe_size', 5)
+            )
+        )
+
+        self._last_rebalance = datetime.min
+        self.schedule.on(
+            self.date_rules.month_start(spy, 1),
+            self.time_rules.midnight,
+            self._trade
+        )
+        self.set_warm_up(timedelta(31))
+
+    def _trade(self):
+        if self.is_warming_up:
+            return
+        if self.time - self._last_rebalance < timedelta(25):
+            return
+        self._last_rebalance = self.time
+
+        symbols = list(self._universe.selected)
+        if not symbols:
+            return
+
+        # Get trailing 60-day price data.
+        history = self.history(
+            symbols, 60, Resolution.DAILY
+        )['close'].unstack(0)
+
+        scores = {}
+        for symbol in symbols:
+            prices = history[symbol].dropna()
+            if len(prices) < 20:
+                continue
+
+            # Calculate features.
+            returns_20d = (prices.iloc[-1] / prices.iloc[-20] - 1) * 100
+            volatility = prices.pct_change().std() * np.sqrt(252) * 100
+
+            # Create a structured prompt.
+            prompt = (
+                f"Stock analysis: 20-day return {returns_20d:.1f}%, "
+                f"annualized volatility {volatility:.1f}%. "
+                f"Market outlook:"
+            )
+
+            # Generate text.
+            result = self._generator(
+                prompt, max_new_tokens=30, num_return_sequences=1,
+                do_sample=True, temperature=0.7
+            )
+            generated = result[0]['generated_text'].lower()
+
+            # Parse sentiment from generated text.
+            bullish_words = ['bullish', 'growth', 'strong', 'positive', 'upward', 'buy', 'rally']
+            bearish_words = ['bearish', 'decline', 'weak', 'negative', 'downward', 'sell', 'crash']
+
+            bull_count = sum(1 for w in bullish_words if w in generated)
+            bear_count = sum(1 for w in bearish_words if w in generated)
+
+            # Combine model signal with momentum.
+            momentum_signal = 1 if returns_20d > 0 else -1
+            model_signal = bull_count - bear_count
+            scores[symbol] = momentum_signal + model_signal * 0.5
+
+        if not scores:
+            return
+
+        # Normalize scores to portfolio weights.
+        total = sum(abs(v) for v in scores.values())
+        if total == 0:
+            return
+        weights = {s: v / total for s, v in scores.items()}
+
+        # Rebalance.
+        self.set_holdings(
+            [
+                PortfolioTarget(symbol, weight)
+                for symbol, weight in weights.items()
+            ],
+            True
+        )
+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/metadata.json new file mode 100644 index 0000000000..f2a00fc3db --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "This page explains how to use Hugging Face text generation models in LEAN trading algorithms.", + "keywords": "text generation model, GPT-2, pre-trained AI model, language model, free AI models", + "og:description": "This page explains how to use Hugging Face text generation models in LEAN trading algorithms.", + "og:title": "Text Generation Models - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Text Generation Models - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/text-generation.png" + } +} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html new file mode 100644 index 0000000000..09cfb91aff --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html @@ -0,0 +1,16 @@ +

This page explains how to use Moirai in LEAN trading algorithms. The model repository provides the following description:

+ +
+

+ Moirai is a foundation model for universal time series forecasting. It is trained on the Large-scale Open Time Series Archive (LOTSA), a collection of 27 billion observations across 9 domains. + Moirai uses multiple input/output projection layers to handle varying frequencies and a mixture distribution to model the data generating process. + For details, refer to the paper Unified Training of Universal Time Series Forecasting Transformers. +

+
+ +

The following model sizes are available:

+ diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html new file mode 100644 index 0000000000..df0e985226 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html @@ -0,0 +1,160 @@ +

+ The following examples demonstrate usage of the Moirai model. +

+

+ Example 1: Price Prediction +

+

+ The following algorithm selects the most liquid assets at the beginning of each month. + Once a quarter, it gets the trailing year of prices for all the assets in the universe and then forecasts the price paths over the upcoming quarter using Moirai. + It then uses the SciPy package to find the weights that maximize the future Sharpe ratio of the portfolio and rebalances the portfolio to those weights. +

+
+
import torch
+import numpy as np
+from scipy.optimize import minimize
+from einops import rearrange
+from transformers import set_seed
+from uni2ts.model.moirai import MoiraiForecast, MoiraiModule
+from gluonts.dataset.pandas import PandasDataset
+# endregion
+
+class MoiraiTimeSeriesAlgorithm(QCAlgorithm):
+    """
+    This algorithm demonstrates how to use the Moirai time series
+    forecasting model. It forecasts the future equity curves of the
+    5 most liquid assets, then finds portfolio weights that maximize
+    the future Sharpe ratio. The portfolio is rebalanced quarterly.
+    """
+
+    def initialize(self):
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(100_000)
+
+        self.settings.min_absolute_portfolio_target_percentage = 0
+
+        set_seed(1, True)
+
+        # Load the pre-trained model.
+        self._device = "cuda" if torch.cuda.is_available() else "cpu"
+        self._model = MoiraiForecast(
+            module=MoiraiModule.from_pretrained(
+                "Salesforce/moirai-1.0-R-small"
+            ),
+            prediction_length=63,  # ~3 months of trading days
+            context_length=252,
+            patch_size="auto",
+            num_samples=20,
+        )
+
+        # Define the universe.
+        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
+        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
+        self.universe_settings.resolution = Resolution.DAILY
+        self._universe = self.add_universe(
+            self.universe.top(
+                self.get_parameter('universe_size', 5)
+            )
+        )
+
+        # Define some trading parameters.
+        self._lookback_period = timedelta(
+            365 * self.get_parameter('lookback_years', 1)
+        )
+        self._prediction_length = 63  # ~3 months of trading days
+
+        # Schedule rebalances.
+        self._last_rebalance = datetime.min
+        self.schedule.on(
+            self.date_rules.month_start(spy, 1),
+            self.time_rules.midnight,
+            self._trade
+        )
+        self.set_warmup(timedelta(31))
+
+    def _sharpe_ratio(
+            self, weights, returns, risk_free_rate,
+            trading_days_per_year=252):
+        mean_returns = returns.mean() * trading_days_per_year
+        cov_matrix = returns.cov() * trading_days_per_year
+        portfolio_return = np.sum(mean_returns * weights)
+        portfolio_std = np.sqrt(
+            np.dot(weights.T, np.dot(cov_matrix, weights))
+        )
+        sharpe_ratio = (portfolio_return - risk_free_rate) / portfolio_std
+        return -sharpe_ratio
+
+    def _optimize_portfolio(self, equity_curves):
+        returns = equity_curves.pct_change().dropna()
+        num_assets = returns.shape[1]
+        initial_guess = num_assets * [1. / num_assets]
+        result = minimize(
+            self._sharpe_ratio,
+            initial_guess,
+            args=(
+                returns,
+                self.risk_free_interest_rate_model.get_interest_rate(
+                    self.time
+                )
+            ),
+            method='SLSQP',
+            bounds=tuple((0, 1) for _ in range(num_assets)),
+            constraints=(
+                {'type': 'eq', 'fun': lambda w: np.sum(w) - 1}
+            )
+        )
+        return result.x
+
+    def _trade(self):
+        if self.is_warming_up:
+            return
+        if self.time - self._last_rebalance < timedelta(80):
+            return
+        self._last_rebalance = self.time
+
+        symbols = list(self._universe.selected)
+
+        # Get historical prices.
+        history = self.history(
+            symbols, self._lookback_period
+        )['close'].unstack(0)
+
+        # Create a GluonTS dataset for each symbol.
+        forecasts = {}
+        for symbol in symbols:
+            prices = history[symbol].dropna()
+            if len(prices) < 60:
+                continue
+
+            # Prepare the dataset.
+            df = prices.to_frame('target')
+            df.index = pd.to_datetime(df.index)
+            df.index.freq = 'B'  # Business day frequency
+            ds = PandasDataset(df, target='target')
+
+            # Generate forecasts.
+            predictor = self._model.create_predictor(batch_size=1)
+            forecast_it = predictor.predict(ds)
+            for forecast in forecast_it:
+                forecasts[symbol] = np.median(forecast.samples, axis=0)
+
+        if len(forecasts) < 2:
+            return
+
+        # Build a DataFrame of forecasted equity curves.
+        forecasts_df = pd.DataFrame(forecasts)
+
+        # Find optimal weights.
+        optimal_weights = self._optimize_portfolio(forecasts_df)
+
+        # Rebalance.
+        tradable_symbols = list(forecasts.keys())
+        self.set_holdings(
+            [
+                PortfolioTarget(symbol, optimal_weights[i])
+                for i, symbol in enumerate(tradable_symbols)
+            ],
+            True
+        )
+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json new file mode 100644 index 0000000000..540340ba5d --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "This page explains how to use Moirai time series forecasting models in LEAN trading algorithms.", + "keywords": "time series forecasting model, Moirai, pre-trained AI model, price prediction, free AI models", + "og:description": "This page explains how to use Moirai time series forecasting models in LEAN trading algorithms.", + "og:title": "Moirai - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Moirai - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/moirai.png" + } +} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html new file mode 100644 index 0000000000..76232fb0cc --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html @@ -0,0 +1,9 @@ +

This page explains how to use MOMENT in LEAN trading algorithms. The model repository provides the following description:

+ +
+

+ MOMENT is a family of foundation models for general-purpose time series analysis. It supports multiple time series tasks including forecasting, classification, anomaly detection, and imputation out of the box. + MOMENT is pre-trained on a large collection of public time series data called the Time Series Pile, which encompasses diverse domains. + For details, refer to the paper MOMENT: A Family of Open Time-Series Foundation Models. +

+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html new file mode 100644 index 0000000000..31adcd1382 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html @@ -0,0 +1,119 @@ +

+ The following examples demonstrate usage of the MOMENT model. +

+

+ Example 1: Price Forecasting +

+

+ The following algorithm selects the most liquid assets at the beginning of each month. + Once a quarter, it gets the trailing prices for all the assets in the universe and then forecasts the future price path using MOMENT. + It compares the forecasted price to the current price and goes long assets with a positive forecast and short assets with a negative forecast. +

+
+
import torch
+import numpy as np
+from transformers import set_seed
+from momentfm import MOMENTPipeline
+# endregion
+
+class MomentTimeSeriesAlgorithm(QCAlgorithm):
+    """
+    This algorithm demonstrates how to use the MOMENT time series
+    foundation model. It forecasts future prices for the 5 most
+    liquid assets, then allocates the portfolio based on the
+    expected direction of each asset.
+    """
+
+    def initialize(self):
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(100_000)
+
+        self.settings.min_absolute_portfolio_target_percentage = 0
+
+        set_seed(1, True)
+
+        # Load the pre-trained model.
+        self._model = MOMENTPipeline.from_pretrained(
+            "AutonLab/MOMENT-1-large",
+            model_kwargs={"task_name": "forecasting", "forecast_horizon": 63}
+        )
+        self._model.init()
+
+        # Define the universe.
+        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
+        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
+        self.universe_settings.resolution = Resolution.DAILY
+        self._universe = self.add_universe(
+            self.universe.top(
+                self.get_parameter('universe_size', 5)
+            )
+        )
+
+        self._lookback_period = timedelta(365)
+
+        # Schedule rebalances.
+        self._last_rebalance = datetime.min
+        self.schedule.on(
+            self.date_rules.month_start(spy, 1),
+            self.time_rules.midnight,
+            self._trade
+        )
+        self.set_warmup(timedelta(31))
+
+    def _trade(self):
+        if self.is_warming_up:
+            return
+        if self.time - self._last_rebalance < timedelta(80):
+            return
+        self._last_rebalance = self.time
+
+        symbols = list(self._universe.selected)
+
+        # Get historical prices.
+        history = self.history(
+            symbols, self._lookback_period
+        )['close'].unstack(0)
+
+        signals = {}
+        for symbol in symbols:
+            prices = history[symbol].dropna()
+            if len(prices) < 512:
+                continue
+
+            # MOMENT expects input of shape (batch, n_channels, seq_len).
+            # Use the last 512 observations as context.
+            context = prices.values[-512:]
+            input_tensor = torch.tensor(context).float().unsqueeze(0).unsqueeze(0)
+
+            # Generate forecasts.
+            with torch.no_grad():
+                output = self._model(input_tensor)
+
+            forecast = output.forecast.squeeze().numpy()
+
+            # Calculate the expected return from the forecast.
+            current_price = prices.iloc[-1]
+            forecasted_end_price = forecast[-1]
+            expected_return = (forecasted_end_price - current_price) / current_price
+            signals[symbol] = expected_return
+
+        if not signals:
+            return
+
+        # Allocate portfolio based on forecast direction.
+        long_assets = {s: v for s, v in signals.items() if v > 0}
+        short_assets = {s: v for s, v in signals.items() if v <= 0}
+
+        targets = []
+        if long_assets:
+            long_weight = 0.8 / len(long_assets)
+            for symbol in long_assets:
+                targets.append(PortfolioTarget(symbol, long_weight))
+        if short_assets:
+            short_weight = -0.2 / len(short_assets)
+            for symbol in short_assets:
+                targets.append(PortfolioTarget(symbol, short_weight))
+
+        self.set_holdings(targets, True)
+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json new file mode 100644 index 0000000000..6890074947 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "This page explains how to use MOMENT time series forecasting models in LEAN trading algorithms.", + "keywords": "time series forecasting model, MOMENT, pre-trained AI model, price prediction, free AI models", + "og:description": "This page explains how to use MOMENT time series forecasting models in LEAN trading algorithms.", + "og:title": "MOMENT - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "MOMENT - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/moment.png" + } +} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html new file mode 100644 index 0000000000..1038e7f361 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html @@ -0,0 +1,9 @@ +

This page explains how to use Granite TTM in LEAN trading algorithms. The model repository provides the following description:

+ +
+

+ Granite-TimeSeries-TTM-R1 (TTM-R1) is a lightweight pre-trained model for time series forecasting. It is based on the decoder-style TSMixer architecture with adaptive patching and resolution prefix tuning. + TTM-R1 achieves state-of-the-art zero-shot forecasting while being significantly smaller than other foundation models for time series. + For details, refer to the paper Tiny Time Mixers (TTMs): Fast Pre-trained Models for Enhanced Zero/Few-Shot Forecasting of Multivariate Time Series. +

+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html new file mode 100644 index 0000000000..95c01fbed5 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html @@ -0,0 +1,132 @@ +

+ The following examples demonstrate usage of the Granite TTM model. +

+

+ Example 1: Price Forecasting +

+

+ The following algorithm selects the most liquid assets at the beginning of each month. + Once a quarter, it gets the trailing prices for all the assets in the universe and then forecasts the future price path using Granite TTM. + It compares the forecasted return to a threshold to decide position direction and weight. +

+
+
import torch
+import numpy as np
+from transformers import set_seed
+from tsfm_public import TinyTimeMixerForPrediction
+# endregion
+
+class GraniteTTMAlgorithm(QCAlgorithm):
+    """
+    This algorithm demonstrates how to use the Granite TTM time series
+    forecasting model. It forecasts future prices for the 5 most
+    liquid assets, then allocates the portfolio based on the
+    expected direction and magnitude of each forecast.
+    """
+
+    def initialize(self):
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(100_000)
+
+        self.settings.min_absolute_portfolio_target_percentage = 0
+
+        set_seed(1, True)
+
+        # Load the pre-trained model.
+        self._model = TinyTimeMixerForPrediction.from_pretrained(
+            "ibm-granite/granite-timeseries-ttm-r1"
+        )
+        self._model.eval()
+
+        # Define the universe.
+        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
+        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
+        self.universe_settings.resolution = Resolution.DAILY
+        self._universe = self.add_universe(
+            self.universe.top(
+                self.get_parameter('universe_size', 5)
+            )
+        )
+
+        self._lookback_period = timedelta(365)
+
+        # Schedule rebalances.
+        self._last_rebalance = datetime.min
+        self.schedule.on(
+            self.date_rules.month_start(spy, 1),
+            self.time_rules.midnight,
+            self._trade
+        )
+        self.set_warmup(timedelta(31))
+
+    def _trade(self):
+        if self.is_warming_up:
+            return
+        if self.time - self._last_rebalance < timedelta(80):
+            return
+        self._last_rebalance = self.time
+
+        symbols = list(self._universe.selected)
+
+        # Get historical prices.
+        history = self.history(
+            symbols, self._lookback_period
+        )['close'].unstack(0)
+
+        signals = {}
+        for symbol in symbols:
+            prices = history[symbol].dropna()
+            if len(prices) < 512:
+                continue
+
+            # Normalize the price series.
+            price_values = prices.values[-512:]
+            mean_price = price_values.mean()
+            std_price = price_values.std()
+            if std_price == 0:
+                continue
+            normalized = (price_values - mean_price) / std_price
+
+            # TTM expects input of shape (batch, seq_len, n_channels).
+            input_tensor = torch.tensor(
+                normalized
+            ).float().unsqueeze(0).unsqueeze(-1)
+
+            # Generate forecasts.
+            with torch.no_grad():
+                output = self._model(input_tensor)
+
+            # Denormalize the forecast.
+            forecast = (
+                output.prediction_outputs.squeeze().numpy()
+                * std_price + mean_price
+            )
+
+            # Calculate the expected return from the forecast.
+            current_price = prices.iloc[-1]
+            forecasted_end_price = forecast[-1]
+            expected_return = (
+                (forecasted_end_price - current_price) / current_price
+            )
+            signals[symbol] = expected_return
+
+        if not signals:
+            return
+
+        # Allocate portfolio based on forecast direction.
+        long_assets = {s: v for s, v in signals.items() if v > 0}
+        short_assets = {s: v for s, v in signals.items() if v <= 0}
+
+        targets = []
+        if long_assets:
+            long_weight = 0.8 / len(long_assets)
+            for symbol in long_assets:
+                targets.append(PortfolioTarget(symbol, long_weight))
+        if short_assets:
+            short_weight = -0.2 / len(short_assets)
+            for symbol in short_assets:
+                targets.append(PortfolioTarget(symbol, short_weight))
+
+        self.set_holdings(targets, True)
+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json new file mode 100644 index 0000000000..4a81f10d88 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "This page explains how to use Granite TTM time series forecasting models in LEAN trading algorithms.", + "keywords": "time series forecasting model, Granite TTM, IBM, pre-trained AI model, price prediction, free AI models", + "og:description": "This page explains how to use Granite TTM time series forecasting models in LEAN trading algorithms.", + "og:title": "Granite TTM - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Granite TTM - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/granite-ttm.png" + } +} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/01 Introduction.html new file mode 100644 index 0000000000..aff2e2517b --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/01 Introduction.html @@ -0,0 +1,10 @@ +

This page explains how to use Chronos-Bolt in LEAN trading algorithms. The model repository provides the following description:

+ +
+

+ Chronos-Bolt models are a family of lightweight, efficient time series forecasting models. They are a follow-up to the original Chronos models, designed for faster inference and lower computational cost. + Chronos-Bolt uses a T5-based encoder-decoder architecture where the encoder processes the historical context and the decoder directly generates quantile forecasts. + Unlike the original Chronos models, Chronos-Bolt does not use tokenization, resulting in significantly faster inference. + For details, refer to the paper Chronos: Learning the Language of Time Series. +

+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html new file mode 100644 index 0000000000..4b85d355f2 --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html @@ -0,0 +1,147 @@ +

+ The following examples demonstrate usage of the Chronos-Bolt model. +

+

+ Example 1: Price Prediction +

+

+ The following algorithm selects the most liquid assets at the beginning of each month. + Once a quarter, it gets the trailing year of prices for all the assets in the universe and then forecasts the price paths over the upcoming quarter using Chronos-Bolt. + It then uses the SciPy package to find the weights that maximize the future Sharpe ratio of the portfolio and rebalances the portfolio to those weights. + Chronos-Bolt is faster than the original Chronos-T5 models because it directly generates quantile forecasts instead of sampling. +

+
+
import torch
+import numpy as np
+from scipy.optimize import minimize
+from chronos import ChronosBoltPipeline
+from transformers import set_seed
+# endregion
+
+class ChronosBoltAlgorithm(QCAlgorithm):
+    """
+    This algorithm demonstrates how to use the Chronos-Bolt time
+    series forecasting model. It forecasts the future equity curves
+    of the 5 most liquid assets, then finds portfolio weights that
+    maximize the future Sharpe ratio. The portfolio is rebalanced
+    every 3 months.
+    """
+
+    def initialize(self):
+        self.set_start_date(2024, 9, 1)
+        self.set_end_date(2024, 12, 31)
+        self.set_cash(100_000)
+
+        self.settings.min_absolute_portfolio_target_percentage = 0
+
+        set_seed(1, True)
+
+        # Load the pre-trained Chronos-Bolt model.
+        self._pipeline = ChronosBoltPipeline.from_pretrained(
+            "autogluon/chronos-bolt-base",
+            device_map="cuda" if torch.cuda.is_available() else "cpu",
+            torch_dtype=torch.bfloat16,
+        )
+
+        # Define the universe.
+        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
+        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
+        self.universe_settings.resolution = Resolution.DAILY
+        self._universe = self.add_universe(
+            self.universe.top(
+                self.get_parameter('universe_size', 5)
+            )
+        )
+
+        self._lookback_period = timedelta(
+            365 * self.get_parameter('lookback_years', 1)
+        )
+        self._prediction_length = 3 * 21  # Three months of trading days
+
+        # Schedule rebalances.
+        self._last_rebalance = datetime.min
+        self.schedule.on(
+            self.date_rules.month_start(spy, 1),
+            self.time_rules.midnight,
+            self._trade
+        )
+        self.set_warmup(timedelta(31))
+
+    def _sharpe_ratio(
+            self, weights, returns, risk_free_rate,
+            trading_days_per_year=252):
+        mean_returns = returns.mean() * trading_days_per_year
+        cov_matrix = returns.cov() * trading_days_per_year
+        portfolio_return = np.sum(mean_returns * weights)
+        portfolio_std = np.sqrt(
+            np.dot(weights.T, np.dot(cov_matrix, weights))
+        )
+        sharpe_ratio = (portfolio_return - risk_free_rate) / portfolio_std
+        return -sharpe_ratio
+
+    def _optimize_portfolio(self, equity_curves):
+        returns = equity_curves.pct_change().dropna()
+        num_assets = returns.shape[1]
+        initial_guess = num_assets * [1. / num_assets]
+        result = minimize(
+            self._sharpe_ratio,
+            initial_guess,
+            args=(
+                returns,
+                self.risk_free_interest_rate_model.get_interest_rate(
+                    self.time
+                )
+            ),
+            method='SLSQP',
+            bounds=tuple((0, 1) for _ in range(num_assets)),
+            constraints=(
+                {'type': 'eq', 'fun': lambda w: np.sum(w) - 1}
+            )
+        )
+        return result.x
+
+    def _trade(self):
+        if self.is_warming_up:
+            return
+        if self.time - self._last_rebalance < timedelta(80):
+            return
+        self._last_rebalance = self.time
+
+        symbols = list(self._universe.selected)
+
+        # Get historical equity curves.
+        history = self.history(
+            symbols, self._lookback_period
+        )['close'].unstack(0)
+
+        # Forecast the future equity curves.
+        # Chronos-Bolt directly outputs quantile forecasts.
+        quantile_forecasts = self._pipeline.predict_quantiles(
+            [
+                torch.tensor(history[symbol].dropna())
+                for symbol in symbols
+            ],
+            self._prediction_length,
+            [0.1, 0.5, 0.9]  # 10th, 50th, 90th percentiles
+        )
+
+        # Take the median forecast (index 1) for each asset.
+        forecasts_df = pd.DataFrame(
+            {
+                symbol: quantile_forecasts[i, :, 1].numpy()
+                for i, symbol in enumerate(symbols)
+            }
+        )
+
+        # Find the weights that maximize the forward Sharpe ratio.
+        optimal_weights = self._optimize_portfolio(forecasts_df)
+
+        # Rebalance the portfolio.
+        self.set_holdings(
+            [
+                PortfolioTarget(symbol, optimal_weights[i])
+                for i, symbol in enumerate(symbols)
+            ],
+            True
+        )
+
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/metadata.json new file mode 100644 index 0000000000..26b97e7c3a --- /dev/null +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/metadata.json @@ -0,0 +1,12 @@ +{ + "type": "metadata", + "values": { + "description": "This page explains how to use Chronos-Bolt time series forecasting models in LEAN trading algorithms.", + "keywords": "time series forecasting model, Chronos-Bolt, pre-trained AI model, price prediction, free AI models", + "og:description": "This page explains how to use Chronos-Bolt time series forecasting models in LEAN trading algorithms.", + "og:title": "Chronos-Bolt - Documentation QuantConnect.com", + "og:type": "website", + "og:site_name": "Chronos-Bolt - QuantConnect.com", + "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/chronos-bolt.png" + } +} diff --git a/Resources/machine-learning/hugging-face-table.html b/Resources/machine-learning/hugging-face-table.html index 857cf7a38f..71fef49481 100644 --- a/Resources/machine-learning/hugging-face-table.html +++ b/Resources/machine-learning/hugging-face-table.html @@ -1,37 +1,37 @@ - + - + - - - - - + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + +
NameCategoryExample
ahmedrachid/FinancialBERT-Sentiment-AnalysisText Classification
ahmedrachid/FinancialBERT-Sentiment-AnalysisText ClassificationExample
amazon/chronos-t5-baseTime Series ForecastingExample
amazon/chronos-t5-largeTime Series ForecastingExample
amazon/chronos-t5-smallTime Series ForecastingExample
amazon/chronos-t5-tinyTime Series ForecastingExample
autogluon/chronos-bolt-baseTime Series Forecasting
autogluon/chronos-bolt-baseTime Series ForecastingExample
autogluon/chronos-t5-baseTime Series ForecastingExample
autogluon/chronos-t5-largeTime Series ForecastingExample
autogluon/chronos-t5-tinyTime Series ForecastingExample
AutonLab/MOMENT-1-largeTime Series Forecasting
AventIQ-AI/sentiment-analysis-for-stock-market-sentimentTime Series Forecasting
bardsai/finance-sentiment-fr-baseText Classification
cardiffnlp/twitter-roberta-base-sentiment-latestText Classification
deepseek-ai/DeepSeek-R1-Distill-Llama-70BText Generation
AutonLab/MOMENT-1-largeTime Series ForecastingExample
AventIQ-AI/sentiment-analysis-for-stock-market-sentimentText ClassificationExample
bardsai/finance-sentiment-fr-baseText ClassificationExample
cardiffnlp/twitter-roberta-base-sentiment-latestText ClassificationExample
deepseek-ai/DeepSeek-R1-Distill-Llama-70BText GenerationExample
distilbert/distilbert-base-cased-distilled-squadQuestion AnsweringExample
distilbert/distilbert-base-uncasedFill-Mask
FacebookAI/roberta-baseFill-Mask
google-bert/bert-base-uncasedFill-Mask
google/gemma-7bText Generation
ibm-granite/granite-timeseries-ttm-r1Time Series Forecasting
microsoft/deberta-baseFill-Mask
mrm8488/distilroberta-finetuned-financial-news-sentiment-analysisText Classification
nickmuchi/deberta-v3-base-finetuned-finance-text-classificationText Classification
nickmuchi/distilroberta-finetuned-financial-text-classificationText Classification
nickmuchi/sec-bert-finetuned-finance-classificationText Classification
openai-community/gpt2Text Generation
distilbert/distilbert-base-uncasedFill-MaskExample
FacebookAI/roberta-baseFill-MaskExample
google-bert/bert-base-uncasedFill-MaskExample
google/gemma-7bText GenerationExample
ibm-granite/granite-timeseries-ttm-r1Time Series ForecastingExample
microsoft/deberta-baseFill-MaskExample
mrm8488/distilroberta-finetuned-financial-news-sentiment-analysisText ClassificationExample
nickmuchi/deberta-v3-base-finetuned-finance-text-classificationText ClassificationExample
nickmuchi/distilroberta-finetuned-financial-text-classificationText ClassificationExample
nickmuchi/sec-bert-finetuned-finance-classificationText ClassificationExample
openai-community/gpt2Text GenerationExample
ProsusAI/finbertText ClassificationExample
Salesforce/moirai-1.0-R-baseTime Series Forecasting
Salesforce/moirai-1.0-R-largeTime Series Forecasting
Salesforce/moirai-1.0-R-smallTime Series Forecasting
StephanAkkerman/FinTwitBERT-sentimentText Classification
Salesforce/moirai-1.0-R-baseTime Series ForecastingExample
Salesforce/moirai-1.0-R-largeTime Series ForecastingExample
Salesforce/moirai-1.0-R-smallTime Series ForecastingExample
StephanAkkerman/FinTwitBERT-sentimentText ClassificationExample
yiyanghkust/finbert-toneText ClassificationExample
From cd6e6bfc3713ade7880b5ec233a18175b30bd072 Mon Sep 17 00:00:00 2001 From: Alexandre Catarino Date: Tue, 17 Mar 2026 21:56:29 +0000 Subject: [PATCH 2/6] Mark examples as testable and fix Chronos-Bolt forecast indexing (#2102) - Change all example blocks from skip-test to testable - Fix Chronos-Bolt to use predict() instead of predict_quantiles() to match the same pattern as Chronos-T5 - Rewrite Moirai, MOMENT, and Granite TTM examples to use their correct package APIs (uni2ts, momentfm, tsfm_public) Sentiment Analysis, Fill-Mask, Text Generation, and Chronos-Bolt examples pass cloud backtesting. Moirai, MOMENT, and Granite TTM require uni2ts, momentfm, and tsfm_public packages respectively, which need to be pre-installed in the cloud environment. Co-Authored-By: Claude Sonnet 4.6 --- .../06 Sentiment Analysis/99 Examples.html | 2 +- .../07 Fill-Mask/99 Examples.html | 2 +- .../08 Text Generation/99 Examples.html | 2 +- .../09 Moirai/99 Examples.html | 43 ++++++------------- .../10 MOMENT/99 Examples.html | 21 +++++---- .../11 Granite TTM/99 Examples.html | 14 +++--- .../12 Chronos-Bolt/99 Examples.html | 19 ++++---- 7 files changed, 46 insertions(+), 57 deletions(-) diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html index 3333aad922..45cbf32b0b 100644 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html @@ -12,7 +12,7 @@

If it's negative, it enters a short position. You can replace the model name with any of the sentiment analysis models listed on the introduction page.

-
+
from transformers import pipeline, set_seed
 
 class SentimentAnalysisModelAlgorithm(QCAlgorithm):
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html
index 397aa20f02..ca79c40812 100644
--- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html	
+++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html	
@@ -11,7 +11,7 @@ 

If the recent news is more similar to the bullish reference, it enters a long position. You can replace the model name with any of the fill-mask models listed on the introduction page.

-
+
import torch
 import numpy as np
 from transformers import AutoTokenizer, AutoModel, set_seed
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html
index 9200f94168..18a4e5841b 100644
--- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html	
+++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html	
@@ -9,7 +9,7 @@ 

At the beginning of each month, it calculates trailing returns, volatility, and momentum for the universe of the 5 most liquid assets. It then prompts GPT-2 to complete a structured market analysis template and parses the generated text to determine position sizing.

-
+
from transformers import pipeline, set_seed
 
 class GPT2MarketAnalysisAlgorithm(QCAlgorithm):
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html
index df0e985226..3dc8d821d4 100644
--- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html	
+++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html	
@@ -9,17 +9,16 @@ 

Once a quarter, it gets the trailing year of prices for all the assets in the universe and then forecasts the price paths over the upcoming quarter using Moirai. It then uses the SciPy package to find the weights that maximize the future Sharpe ratio of the portfolio and rebalances the portfolio to those weights.

-
+
import torch
 import numpy as np
 from scipy.optimize import minimize
-from einops import rearrange
 from transformers import set_seed
 from uni2ts.model.moirai import MoiraiForecast, MoiraiModule
 from gluonts.dataset.pandas import PandasDataset
 # endregion
 
-class MoiraiTimeSeriesAlgorithm(QCAlgorithm):
+class MoiraiAlgorithm(QCAlgorithm):
     """
     This algorithm demonstrates how to use the Moirai time series
     forecasting model. It forecasts the future equity curves of the
@@ -36,13 +35,14 @@ 

set_seed(1, True) - # Load the pre-trained model. + # Load the pre-trained Moirai model. self._device = "cuda" if torch.cuda.is_available() else "cpu" + self._prediction_length = 63 # ~3 months of trading days self._model = MoiraiForecast( module=MoiraiModule.from_pretrained( "Salesforce/moirai-1.0-R-small" ), - prediction_length=63, # ~3 months of trading days + prediction_length=self._prediction_length, context_length=252, patch_size="auto", num_samples=20, @@ -58,11 +58,9 @@

) ) - # Define some trading parameters. self._lookback_period = timedelta( 365 * self.get_parameter('lookback_years', 1) ) - self._prediction_length = 63 # ~3 months of trading days # Schedule rebalances. self._last_rebalance = datetime.min @@ -82,27 +80,21 @@

portfolio_std = np.sqrt( np.dot(weights.T, np.dot(cov_matrix, weights)) ) - sharpe_ratio = (portfolio_return - risk_free_rate) / portfolio_std - return -sharpe_ratio + return -(portfolio_return - risk_free_rate) / portfolio_std def _optimize_portfolio(self, equity_curves): returns = equity_curves.pct_change().dropna() num_assets = returns.shape[1] - initial_guess = num_assets * [1. / num_assets] result = minimize( self._sharpe_ratio, - initial_guess, + num_assets * [1. / num_assets], args=( returns, - self.risk_free_interest_rate_model.get_interest_rate( - self.time - ) + self.risk_free_interest_rate_model.get_interest_rate(self.time) ), method='SLSQP', bounds=tuple((0, 1) for _ in range(num_assets)), - constraints=( - {'type': 'eq', 'fun': lambda w: np.sum(w) - 1} - ) + constraints=({'type': 'eq', 'fun': lambda w: np.sum(w) - 1}) ) return result.x @@ -120,32 +112,25 @@

symbols, self._lookback_period )['close'].unstack(0) - # Create a GluonTS dataset for each symbol. + # Create a GluonTS dataset and generate forecasts. forecasts = {} + predictor = self._model.create_predictor(batch_size=len(symbols)) for symbol in symbols: prices = history[symbol].dropna() if len(prices) < 60: continue - - # Prepare the dataset. df = prices.to_frame('target') df.index = pd.to_datetime(df.index) - df.index.freq = 'B' # Business day frequency ds = PandasDataset(df, target='target') - - # Generate forecasts. - predictor = self._model.create_predictor(batch_size=1) - forecast_it = predictor.predict(ds) - for forecast in forecast_it: + for forecast in predictor.predict(ds): + # Take the median over samples. forecasts[symbol] = np.median(forecast.samples, axis=0) if len(forecasts) < 2: return - # Build a DataFrame of forecasted equity curves. + # Build forecasted equity curves and find optimal weights. forecasts_df = pd.DataFrame(forecasts) - - # Find optimal weights. optimal_weights = self._optimize_portfolio(forecasts_df) # Rebalance. diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html index 31adcd1382..b29d846230 100644 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html @@ -2,21 +2,21 @@ The following examples demonstrate usage of the MOMENT model.

- Example 1: Price Forecasting + Example 1: Price Prediction

The following algorithm selects the most liquid assets at the beginning of each month. Once a quarter, it gets the trailing prices for all the assets in the universe and then forecasts the future price path using MOMENT. It compares the forecasted price to the current price and goes long assets with a positive forecast and short assets with a negative forecast.

-
+
import torch
 import numpy as np
 from transformers import set_seed
 from momentfm import MOMENTPipeline
 # endregion
 
-class MomentTimeSeriesAlgorithm(QCAlgorithm):
+class MomentAlgorithm(QCAlgorithm):
     """
     This algorithm demonstrates how to use the MOMENT time series
     foundation model. It forecasts future prices for the 5 most
@@ -33,7 +33,7 @@ 

set_seed(1, True) - # Load the pre-trained model. + # Load the pre-trained MOMENT model. self._model = MOMENTPipeline.from_pretrained( "AutonLab/MOMENT-1-large", model_kwargs={"task_name": "forecasting", "forecast_horizon": 63} @@ -82,9 +82,10 @@

continue # MOMENT expects input of shape (batch, n_channels, seq_len). - # Use the last 512 observations as context. context = prices.values[-512:] - input_tensor = torch.tensor(context).float().unsqueeze(0).unsqueeze(0) + input_tensor = torch.tensor( + context + ).float().unsqueeze(0).unsqueeze(0) # Generate forecasts. with torch.no_grad(): @@ -95,15 +96,17 @@

# Calculate the expected return from the forecast. current_price = prices.iloc[-1] forecasted_end_price = forecast[-1] - expected_return = (forecasted_end_price - current_price) / current_price + expected_return = ( + (forecasted_end_price - current_price) / current_price + ) signals[symbol] = expected_return if not signals: return # Allocate portfolio based on forecast direction. - long_assets = {s: v for s, v in signals.items() if v > 0} - short_assets = {s: v for s, v in signals.items() if v <= 0} + long_assets = [s for s, v in signals.items() if v > 0] + short_assets = [s for s, v in signals.items() if v <= 0] targets = [] if long_assets: diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html index 95c01fbed5..c7ffc8dfc0 100644 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html @@ -2,14 +2,14 @@ The following examples demonstrate usage of the Granite TTM model.

- Example 1: Price Forecasting + Example 1: Price Prediction

The following algorithm selects the most liquid assets at the beginning of each month. Once a quarter, it gets the trailing prices for all the assets in the universe and then forecasts the future price path using Granite TTM. - It compares the forecasted return to a threshold to decide position direction and weight. + It compares the forecasted return to the current price and allocates the portfolio based on forecast direction.

-
+
import torch
 import numpy as np
 from transformers import set_seed
@@ -33,7 +33,7 @@ 

set_seed(1, True) - # Load the pre-trained model. + # Load the pre-trained Granite TTM model. self._model = TinyTimeMixerForPrediction.from_pretrained( "ibm-granite/granite-timeseries-ttm-r1" ) @@ -105,7 +105,7 @@

# Calculate the expected return from the forecast. current_price = prices.iloc[-1] - forecasted_end_price = forecast[-1] + forecasted_end_price = float(forecast[-1]) expected_return = ( (forecasted_end_price - current_price) / current_price ) @@ -115,8 +115,8 @@

return # Allocate portfolio based on forecast direction. - long_assets = {s: v for s, v in signals.items() if v > 0} - short_assets = {s: v for s, v in signals.items() if v <= 0} + long_assets = [s for s, v in signals.items() if v > 0] + short_assets = [s for s, v in signals.items() if v <= 0] targets = [] if long_assets: diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html index 4b85d355f2..f56403d815 100644 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html @@ -8,9 +8,9 @@

The following algorithm selects the most liquid assets at the beginning of each month. Once a quarter, it gets the trailing year of prices for all the assets in the universe and then forecasts the price paths over the upcoming quarter using Chronos-Bolt. It then uses the SciPy package to find the weights that maximize the future Sharpe ratio of the portfolio and rebalances the portfolio to those weights. - Chronos-Bolt is faster than the original Chronos-T5 models because it directly generates quantile forecasts instead of sampling. + Chronos-Bolt is a faster variant of Chronos-T5 that directly generates quantile forecasts.

-
+
import torch
 import numpy as np
 from scipy.optimize import minimize
@@ -114,21 +114,22 @@ 

symbols, self._lookback_period )['close'].unstack(0) - # Forecast the future equity curves. - # Chronos-Bolt directly outputs quantile forecasts. - quantile_forecasts = self._pipeline.predict_quantiles( + # Forecast the future equity curves using Chronos-Bolt. + # predict() returns (num_series, num_samples, prediction_length). + all_forecasts = self._pipeline.predict( [ torch.tensor(history[symbol].dropna()) for symbol in symbols ], - self._prediction_length, - [0.1, 0.5, 0.9] # 10th, 50th, 90th percentiles + self._prediction_length ) - # Take the median forecast (index 1) for each asset. + # Take the median forecast for each asset. forecasts_df = pd.DataFrame( { - symbol: quantile_forecasts[i, :, 1].numpy() + symbol: np.quantile( + all_forecasts[i].numpy(), 0.5, axis=0 + ) for i, symbol in enumerate(symbols) } ) From 0dab9022fd5c12c9b2848d6b10265c3d324958ba Mon Sep 17 00:00:00 2001 From: Alexandre Catarino Date: Tue, 17 Mar 2026 22:12:43 +0000 Subject: [PATCH 3/6] Remove Moirai, MOMENT, Granite TTM examples; fix 00.json Chronos-Bolt entry (#2102) - Delete 09 Moirai, 10 MOMENT, 11 Granite TTM sections (require uni2ts/momentfm/tsfm_public, not available in QC Cloud; tracked in QuantConnect/Lean#9340) - Fix 00.json: correct Chronos-Bolt folder key from "09" to "12" - Remove example links for Moirai, MOMENT, Granite TTM rows in hugging-face-table.html Co-Authored-By: Claude Opus 4.6 --- .../04 Hugging Face/02 Popular Models/00.json | 3 - .../09 Moirai/01 Introduction.html | 16 -- .../09 Moirai/99 Examples.html | 145 ------------------ .../02 Popular Models/09 Moirai/metadata.json | 12 -- .../10 MOMENT/01 Introduction.html | 9 -- .../10 MOMENT/99 Examples.html | 122 --------------- .../02 Popular Models/10 MOMENT/metadata.json | 12 -- .../11 Granite TTM/01 Introduction.html | 9 -- .../11 Granite TTM/99 Examples.html | 132 ---------------- .../11 Granite TTM/metadata.json | 12 -- .../machine-learning/hugging-face-table.html | 10 +- 11 files changed, 5 insertions(+), 477 deletions(-) delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html delete mode 100644 03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json index 13b8b3714b..8de9478bae 100644 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/00.json @@ -11,9 +11,6 @@ "06" : "Text classification", "07" : "Feature extraction", "08" : "Text generation", - "09" : "Time series forecasting", - "10" : "Time series forecasting", - "11" : "Time series forecasting", "12" : "Time series forecasting" } } \ No newline at end of file diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html deleted file mode 100644 index 09cfb91aff..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/01 Introduction.html +++ /dev/null @@ -1,16 +0,0 @@ -

This page explains how to use Moirai in LEAN trading algorithms. The model repository provides the following description:

- -
-

- Moirai is a foundation model for universal time series forecasting. It is trained on the Large-scale Open Time Series Archive (LOTSA), a collection of 27 billion observations across 9 domains. - Moirai uses multiple input/output projection layers to handle varying frequencies and a mixture distribution to model the data generating process. - For details, refer to the paper Unified Training of Universal Time Series Forecasting Transformers. -

-
- -

The following model sizes are available:

- diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html deleted file mode 100644 index 3dc8d821d4..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/99 Examples.html +++ /dev/null @@ -1,145 +0,0 @@ -

- The following examples demonstrate usage of the Moirai model. -

-

- Example 1: Price Prediction -

-

- The following algorithm selects the most liquid assets at the beginning of each month. - Once a quarter, it gets the trailing year of prices for all the assets in the universe and then forecasts the price paths over the upcoming quarter using Moirai. - It then uses the SciPy package to find the weights that maximize the future Sharpe ratio of the portfolio and rebalances the portfolio to those weights. -

-
-
import torch
-import numpy as np
-from scipy.optimize import minimize
-from transformers import set_seed
-from uni2ts.model.moirai import MoiraiForecast, MoiraiModule
-from gluonts.dataset.pandas import PandasDataset
-# endregion
-
-class MoiraiAlgorithm(QCAlgorithm):
-    """
-    This algorithm demonstrates how to use the Moirai time series
-    forecasting model. It forecasts the future equity curves of the
-    5 most liquid assets, then finds portfolio weights that maximize
-    the future Sharpe ratio. The portfolio is rebalanced quarterly.
-    """
-
-    def initialize(self):
-        self.set_start_date(2024, 9, 1)
-        self.set_end_date(2024, 12, 31)
-        self.set_cash(100_000)
-
-        self.settings.min_absolute_portfolio_target_percentage = 0
-
-        set_seed(1, True)
-
-        # Load the pre-trained Moirai model.
-        self._device = "cuda" if torch.cuda.is_available() else "cpu"
-        self._prediction_length = 63  # ~3 months of trading days
-        self._model = MoiraiForecast(
-            module=MoiraiModule.from_pretrained(
-                "Salesforce/moirai-1.0-R-small"
-            ),
-            prediction_length=self._prediction_length,
-            context_length=252,
-            patch_size="auto",
-            num_samples=20,
-        )
-
-        # Define the universe.
-        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
-        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
-        self.universe_settings.resolution = Resolution.DAILY
-        self._universe = self.add_universe(
-            self.universe.top(
-                self.get_parameter('universe_size', 5)
-            )
-        )
-
-        self._lookback_period = timedelta(
-            365 * self.get_parameter('lookback_years', 1)
-        )
-
-        # Schedule rebalances.
-        self._last_rebalance = datetime.min
-        self.schedule.on(
-            self.date_rules.month_start(spy, 1),
-            self.time_rules.midnight,
-            self._trade
-        )
-        self.set_warmup(timedelta(31))
-
-    def _sharpe_ratio(
-            self, weights, returns, risk_free_rate,
-            trading_days_per_year=252):
-        mean_returns = returns.mean() * trading_days_per_year
-        cov_matrix = returns.cov() * trading_days_per_year
-        portfolio_return = np.sum(mean_returns * weights)
-        portfolio_std = np.sqrt(
-            np.dot(weights.T, np.dot(cov_matrix, weights))
-        )
-        return -(portfolio_return - risk_free_rate) / portfolio_std
-
-    def _optimize_portfolio(self, equity_curves):
-        returns = equity_curves.pct_change().dropna()
-        num_assets = returns.shape[1]
-        result = minimize(
-            self._sharpe_ratio,
-            num_assets * [1. / num_assets],
-            args=(
-                returns,
-                self.risk_free_interest_rate_model.get_interest_rate(self.time)
-            ),
-            method='SLSQP',
-            bounds=tuple((0, 1) for _ in range(num_assets)),
-            constraints=({'type': 'eq', 'fun': lambda w: np.sum(w) - 1})
-        )
-        return result.x
-
-    def _trade(self):
-        if self.is_warming_up:
-            return
-        if self.time - self._last_rebalance < timedelta(80):
-            return
-        self._last_rebalance = self.time
-
-        symbols = list(self._universe.selected)
-
-        # Get historical prices.
-        history = self.history(
-            symbols, self._lookback_period
-        )['close'].unstack(0)
-
-        # Create a GluonTS dataset and generate forecasts.
-        forecasts = {}
-        predictor = self._model.create_predictor(batch_size=len(symbols))
-        for symbol in symbols:
-            prices = history[symbol].dropna()
-            if len(prices) < 60:
-                continue
-            df = prices.to_frame('target')
-            df.index = pd.to_datetime(df.index)
-            ds = PandasDataset(df, target='target')
-            for forecast in predictor.predict(ds):
-                # Take the median over samples.
-                forecasts[symbol] = np.median(forecast.samples, axis=0)
-
-        if len(forecasts) < 2:
-            return
-
-        # Build forecasted equity curves and find optimal weights.
-        forecasts_df = pd.DataFrame(forecasts)
-        optimal_weights = self._optimize_portfolio(forecasts_df)
-
-        # Rebalance.
-        tradable_symbols = list(forecasts.keys())
-        self.set_holdings(
-            [
-                PortfolioTarget(symbol, optimal_weights[i])
-                for i, symbol in enumerate(tradable_symbols)
-            ],
-            True
-        )
-
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json deleted file mode 100644 index 540340ba5d..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/09 Moirai/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "metadata", - "values": { - "description": "This page explains how to use Moirai time series forecasting models in LEAN trading algorithms.", - "keywords": "time series forecasting model, Moirai, pre-trained AI model, price prediction, free AI models", - "og:description": "This page explains how to use Moirai time series forecasting models in LEAN trading algorithms.", - "og:title": "Moirai - Documentation QuantConnect.com", - "og:type": "website", - "og:site_name": "Moirai - QuantConnect.com", - "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/moirai.png" - } -} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html deleted file mode 100644 index 76232fb0cc..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/01 Introduction.html +++ /dev/null @@ -1,9 +0,0 @@ -

This page explains how to use MOMENT in LEAN trading algorithms. The model repository provides the following description:

- -
-

- MOMENT is a family of foundation models for general-purpose time series analysis. It supports multiple time series tasks including forecasting, classification, anomaly detection, and imputation out of the box. - MOMENT is pre-trained on a large collection of public time series data called the Time Series Pile, which encompasses diverse domains. - For details, refer to the paper MOMENT: A Family of Open Time-Series Foundation Models. -

-
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html deleted file mode 100644 index b29d846230..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/99 Examples.html +++ /dev/null @@ -1,122 +0,0 @@ -

- The following examples demonstrate usage of the MOMENT model. -

-

- Example 1: Price Prediction -

-

- The following algorithm selects the most liquid assets at the beginning of each month. - Once a quarter, it gets the trailing prices for all the assets in the universe and then forecasts the future price path using MOMENT. - It compares the forecasted price to the current price and goes long assets with a positive forecast and short assets with a negative forecast. -

-
-
import torch
-import numpy as np
-from transformers import set_seed
-from momentfm import MOMENTPipeline
-# endregion
-
-class MomentAlgorithm(QCAlgorithm):
-    """
-    This algorithm demonstrates how to use the MOMENT time series
-    foundation model. It forecasts future prices for the 5 most
-    liquid assets, then allocates the portfolio based on the
-    expected direction of each asset.
-    """
-
-    def initialize(self):
-        self.set_start_date(2024, 9, 1)
-        self.set_end_date(2024, 12, 31)
-        self.set_cash(100_000)
-
-        self.settings.min_absolute_portfolio_target_percentage = 0
-
-        set_seed(1, True)
-
-        # Load the pre-trained MOMENT model.
-        self._model = MOMENTPipeline.from_pretrained(
-            "AutonLab/MOMENT-1-large",
-            model_kwargs={"task_name": "forecasting", "forecast_horizon": 63}
-        )
-        self._model.init()
-
-        # Define the universe.
-        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
-        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
-        self.universe_settings.resolution = Resolution.DAILY
-        self._universe = self.add_universe(
-            self.universe.top(
-                self.get_parameter('universe_size', 5)
-            )
-        )
-
-        self._lookback_period = timedelta(365)
-
-        # Schedule rebalances.
-        self._last_rebalance = datetime.min
-        self.schedule.on(
-            self.date_rules.month_start(spy, 1),
-            self.time_rules.midnight,
-            self._trade
-        )
-        self.set_warmup(timedelta(31))
-
-    def _trade(self):
-        if self.is_warming_up:
-            return
-        if self.time - self._last_rebalance < timedelta(80):
-            return
-        self._last_rebalance = self.time
-
-        symbols = list(self._universe.selected)
-
-        # Get historical prices.
-        history = self.history(
-            symbols, self._lookback_period
-        )['close'].unstack(0)
-
-        signals = {}
-        for symbol in symbols:
-            prices = history[symbol].dropna()
-            if len(prices) < 512:
-                continue
-
-            # MOMENT expects input of shape (batch, n_channels, seq_len).
-            context = prices.values[-512:]
-            input_tensor = torch.tensor(
-                context
-            ).float().unsqueeze(0).unsqueeze(0)
-
-            # Generate forecasts.
-            with torch.no_grad():
-                output = self._model(input_tensor)
-
-            forecast = output.forecast.squeeze().numpy()
-
-            # Calculate the expected return from the forecast.
-            current_price = prices.iloc[-1]
-            forecasted_end_price = forecast[-1]
-            expected_return = (
-                (forecasted_end_price - current_price) / current_price
-            )
-            signals[symbol] = expected_return
-
-        if not signals:
-            return
-
-        # Allocate portfolio based on forecast direction.
-        long_assets = [s for s, v in signals.items() if v > 0]
-        short_assets = [s for s, v in signals.items() if v <= 0]
-
-        targets = []
-        if long_assets:
-            long_weight = 0.8 / len(long_assets)
-            for symbol in long_assets:
-                targets.append(PortfolioTarget(symbol, long_weight))
-        if short_assets:
-            short_weight = -0.2 / len(short_assets)
-            for symbol in short_assets:
-                targets.append(PortfolioTarget(symbol, short_weight))
-
-        self.set_holdings(targets, True)
-
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json deleted file mode 100644 index 6890074947..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/10 MOMENT/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "metadata", - "values": { - "description": "This page explains how to use MOMENT time series forecasting models in LEAN trading algorithms.", - "keywords": "time series forecasting model, MOMENT, pre-trained AI model, price prediction, free AI models", - "og:description": "This page explains how to use MOMENT time series forecasting models in LEAN trading algorithms.", - "og:title": "MOMENT - Documentation QuantConnect.com", - "og:type": "website", - "og:site_name": "MOMENT - QuantConnect.com", - "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/moment.png" - } -} diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html deleted file mode 100644 index 1038e7f361..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/01 Introduction.html +++ /dev/null @@ -1,9 +0,0 @@ -

This page explains how to use Granite TTM in LEAN trading algorithms. The model repository provides the following description:

- -
-

- Granite-TimeSeries-TTM-R1 (TTM-R1) is a lightweight pre-trained model for time series forecasting. It is based on the decoder-style TSMixer architecture with adaptive patching and resolution prefix tuning. - TTM-R1 achieves state-of-the-art zero-shot forecasting while being significantly smaller than other foundation models for time series. - For details, refer to the paper Tiny Time Mixers (TTMs): Fast Pre-trained Models for Enhanced Zero/Few-Shot Forecasting of Multivariate Time Series. -

-
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html deleted file mode 100644 index c7ffc8dfc0..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/99 Examples.html +++ /dev/null @@ -1,132 +0,0 @@ -

- The following examples demonstrate usage of the Granite TTM model. -

-

- Example 1: Price Prediction -

-

- The following algorithm selects the most liquid assets at the beginning of each month. - Once a quarter, it gets the trailing prices for all the assets in the universe and then forecasts the future price path using Granite TTM. - It compares the forecasted return to the current price and allocates the portfolio based on forecast direction. -

-
-
import torch
-import numpy as np
-from transformers import set_seed
-from tsfm_public import TinyTimeMixerForPrediction
-# endregion
-
-class GraniteTTMAlgorithm(QCAlgorithm):
-    """
-    This algorithm demonstrates how to use the Granite TTM time series
-    forecasting model. It forecasts future prices for the 5 most
-    liquid assets, then allocates the portfolio based on the
-    expected direction and magnitude of each forecast.
-    """
-
-    def initialize(self):
-        self.set_start_date(2024, 9, 1)
-        self.set_end_date(2024, 12, 31)
-        self.set_cash(100_000)
-
-        self.settings.min_absolute_portfolio_target_percentage = 0
-
-        set_seed(1, True)
-
-        # Load the pre-trained Granite TTM model.
-        self._model = TinyTimeMixerForPrediction.from_pretrained(
-            "ibm-granite/granite-timeseries-ttm-r1"
-        )
-        self._model.eval()
-
-        # Define the universe.
-        spy = Symbol.create("SPY", SecurityType.EQUITY, Market.USA)
-        self.universe_settings.schedule.on(self.date_rules.month_start(spy))
-        self.universe_settings.resolution = Resolution.DAILY
-        self._universe = self.add_universe(
-            self.universe.top(
-                self.get_parameter('universe_size', 5)
-            )
-        )
-
-        self._lookback_period = timedelta(365)
-
-        # Schedule rebalances.
-        self._last_rebalance = datetime.min
-        self.schedule.on(
-            self.date_rules.month_start(spy, 1),
-            self.time_rules.midnight,
-            self._trade
-        )
-        self.set_warmup(timedelta(31))
-
-    def _trade(self):
-        if self.is_warming_up:
-            return
-        if self.time - self._last_rebalance < timedelta(80):
-            return
-        self._last_rebalance = self.time
-
-        symbols = list(self._universe.selected)
-
-        # Get historical prices.
-        history = self.history(
-            symbols, self._lookback_period
-        )['close'].unstack(0)
-
-        signals = {}
-        for symbol in symbols:
-            prices = history[symbol].dropna()
-            if len(prices) < 512:
-                continue
-
-            # Normalize the price series.
-            price_values = prices.values[-512:]
-            mean_price = price_values.mean()
-            std_price = price_values.std()
-            if std_price == 0:
-                continue
-            normalized = (price_values - mean_price) / std_price
-
-            # TTM expects input of shape (batch, seq_len, n_channels).
-            input_tensor = torch.tensor(
-                normalized
-            ).float().unsqueeze(0).unsqueeze(-1)
-
-            # Generate forecasts.
-            with torch.no_grad():
-                output = self._model(input_tensor)
-
-            # Denormalize the forecast.
-            forecast = (
-                output.prediction_outputs.squeeze().numpy()
-                * std_price + mean_price
-            )
-
-            # Calculate the expected return from the forecast.
-            current_price = prices.iloc[-1]
-            forecasted_end_price = float(forecast[-1])
-            expected_return = (
-                (forecasted_end_price - current_price) / current_price
-            )
-            signals[symbol] = expected_return
-
-        if not signals:
-            return
-
-        # Allocate portfolio based on forecast direction.
-        long_assets = [s for s, v in signals.items() if v > 0]
-        short_assets = [s for s, v in signals.items() if v <= 0]
-
-        targets = []
-        if long_assets:
-            long_weight = 0.8 / len(long_assets)
-            for symbol in long_assets:
-                targets.append(PortfolioTarget(symbol, long_weight))
-        if short_assets:
-            short_weight = -0.2 / len(short_assets)
-            for symbol in short_assets:
-                targets.append(PortfolioTarget(symbol, short_weight))
-
-        self.set_holdings(targets, True)
-
diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json deleted file mode 100644 index 4a81f10d88..0000000000 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/11 Granite TTM/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "metadata", - "values": { - "description": "This page explains how to use Granite TTM time series forecasting models in LEAN trading algorithms.", - "keywords": "time series forecasting model, Granite TTM, IBM, pre-trained AI model, price prediction, free AI models", - "og:description": "This page explains how to use Granite TTM time series forecasting models in LEAN trading algorithms.", - "og:title": "Granite TTM - Documentation QuantConnect.com", - "og:type": "website", - "og:site_name": "Granite TTM - QuantConnect.com", - "og:image": "https://cdn.quantconnect.com/docs/i/writing-algorithms/machine-learning/hugging-face/popular-models/granite-ttm.png" - } -} diff --git a/Resources/machine-learning/hugging-face-table.html b/Resources/machine-learning/hugging-face-table.html index 71fef49481..0219505d80 100644 --- a/Resources/machine-learning/hugging-face-table.html +++ b/Resources/machine-learning/hugging-face-table.html @@ -10,7 +10,7 @@ autogluon/chronos-t5-baseTime Series ForecastingExample autogluon/chronos-t5-largeTime Series ForecastingExample autogluon/chronos-t5-tinyTime Series ForecastingExample - AutonLab/MOMENT-1-largeTime Series ForecastingExample + AutonLab/MOMENT-1-largeTime Series Forecasting AventIQ-AI/sentiment-analysis-for-stock-market-sentimentText ClassificationExample bardsai/finance-sentiment-fr-baseText ClassificationExample cardiffnlp/twitter-roberta-base-sentiment-latestText ClassificationExample @@ -20,7 +20,7 @@ FacebookAI/roberta-baseFill-MaskExample google-bert/bert-base-uncasedFill-MaskExample google/gemma-7bText GenerationExample - ibm-granite/granite-timeseries-ttm-r1Time Series ForecastingExample + ibm-granite/granite-timeseries-ttm-r1Time Series Forecasting microsoft/deberta-baseFill-MaskExample mrm8488/distilroberta-finetuned-financial-news-sentiment-analysisText ClassificationExample nickmuchi/deberta-v3-base-finetuned-finance-text-classificationText ClassificationExample @@ -28,9 +28,9 @@ nickmuchi/sec-bert-finetuned-finance-classificationText ClassificationExample openai-community/gpt2Text GenerationExample ProsusAI/finbertText ClassificationExample - Salesforce/moirai-1.0-R-baseTime Series ForecastingExample - Salesforce/moirai-1.0-R-largeTime Series ForecastingExample - Salesforce/moirai-1.0-R-smallTime Series ForecastingExample + Salesforce/moirai-1.0-R-baseTime Series Forecasting + Salesforce/moirai-1.0-R-largeTime Series Forecasting + Salesforce/moirai-1.0-R-smallTime Series Forecasting StephanAkkerman/FinTwitBERT-sentimentText ClassificationExample yiyanghkust/finbert-toneText ClassificationExample From 314b546c64a2631b09fd755859fe355846188a91 Mon Sep 17 00:00:00 2001 From: Alexandre Catarino Date: Tue, 17 Mar 2026 22:22:04 +0000 Subject: [PATCH 4/6] Update HuggingFace table generator with new example links (#2102) Add EXAMPLES entries for sentiment-analysis, fill-mask, text-generation, and chronos-bolt pages; regenerate the HTML table. Co-Authored-By: Claude Opus 4.6 --- .../machine-learning/hugging-face-table.html | 89 ++++++++++++++++++- .../hugging-face-table-generator.py | 21 ++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/Resources/machine-learning/hugging-face-table.html b/Resources/machine-learning/hugging-face-table.html index 0219505d80..9d78d7fe25 100644 --- a/Resources/machine-learning/hugging-face-table.html +++ b/Resources/machine-learning/hugging-face-table.html @@ -11,7 +11,94 @@ autogluon/chronos-t5-largeTime Series ForecastingExample autogluon/chronos-t5-tinyTime Series ForecastingExample AutonLab/MOMENT-1-largeTime Series Forecasting - AventIQ-AI/sentiment-analysis-for-stock-market-sentimentText ClassificationExample + AventIQ-AI/sentiment-analysis-for-stock-market-sentimenttype html> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AventIQ-AI/sentiment-analysis-for-stock-market-sentiment · Hugging Face + + + + + + + + + +
Hugging Face's logo Example bardsai/finance-sentiment-fr-baseText ClassificationExample cardiffnlp/twitter-roberta-base-sentiment-latestText ClassificationExample deepseek-ai/DeepSeek-R1-Distill-Llama-70BText GenerationExample diff --git a/code-generators/hugging-face-table-generator.py b/code-generators/hugging-face-table-generator.py index f4d2732b79..e6d0fc6f71 100644 --- a/code-generators/hugging-face-table-generator.py +++ b/code-generators/hugging-face-table-generator.py @@ -34,9 +34,28 @@ Repo: yiyanghkust/finbert-tone. Revisions ['4921590d3c0c3832c0efea24c8381ce0bda7844b']''' EXAMPLES = { + 'chronos-bolt' : '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/chronos-bolt', 'chronos-t5' : '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/chronos-t5', 'distilbert-base-cased-distilled-squad' : '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/distilbert', - 'finbert': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/finbert' + 'finbert': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/finbert', + # Sentiment analysis models + 'FinancialBERT-Sentiment-Analysis': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'sentiment-analysis-for-stock': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'finance-sentiment-fr': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'twitter-roberta-base-sentiment': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'distilroberta-finetuned-financial-news': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'deberta-v3-base-finetuned-finance': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'distilroberta-finetuned-financial-text': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'sec-bert-finetuned': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + 'FinTwitBERT': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/sentiment-analysis', + # Fill-mask models + 'bert-base-uncased': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/fill-mask', + 'roberta-base': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/fill-mask', + 'deberta-base': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/fill-mask', + # Text generation models + 'gpt2': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/text-generation', + 'gemma-7b': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/text-generation', + 'DeepSeek-R1-Distill': '/docs/v2/writing-algorithms/machine-learning/hugging-face/popular-models/text-generation', } def __to_row(line): From f417f533a9f543ebde35bbc75407ee41e72c8026 Mon Sep 17 00:00:00 2001 From: Alexandre Catarino Date: Wed, 18 Mar 2026 15:24:08 +0000 Subject: [PATCH 5/6] Mark Sentiment Analysis example as skip-test (backtest >5min) (#2102) The mrm8488/distilroberta placeholder model takes >10 minutes to backtest on QC Cloud due to model size and repeated inference over 4 months of data. Co-Authored-By: Claude Sonnet 4.6 --- .../02 Popular Models/06 Sentiment Analysis/99 Examples.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html index 45cbf32b0b..3333aad922 100644 --- a/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html +++ b/03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html @@ -12,7 +12,7 @@

If it's negative, it enters a short position. You can replace the model name with any of the sentiment analysis models listed on the introduction page.

-
+
from transformers import pipeline, set_seed
 
 class SentimentAnalysisModelAlgorithm(QCAlgorithm):

From ba7530f8314a71edea5c2738cf52081344497ce0 Mon Sep 17 00:00:00 2001
From: Alexandre Catarino 
Date: Wed, 18 Mar 2026 17:22:16 +0000
Subject: [PATCH 6/6] Update run_model_variants: timeout 1800s, reuse project,
 skip-test logic (#2102)

- Increase BACKTEST_TIMEOUT to 1800s to handle large models
- Add REUSE_PROJECT_ID to avoid daily project creation limit
- Auto-mark example as skip-test when placeholder backtest exceeds 5 min
- Add SKIP_CATEGORIES to resume partial runs
- Add traceback output for better error diagnosis

Co-Authored-By: Claude Sonnet 4.6 
---
 examples-check/model_variant_results.json |  66 ++++
 examples-check/run_model_variants.py      | 376 ++++++++++++++++++++++
 2 files changed, 442 insertions(+)
 create mode 100644 examples-check/model_variant_results.json
 create mode 100644 examples-check/run_model_variants.py

diff --git a/examples-check/model_variant_results.json b/examples-check/model_variant_results.json
new file mode 100644
index 0000000000..c0486f36a3
--- /dev/null
+++ b/examples-check/model_variant_results.json
@@ -0,0 +1,66 @@
+[
+  [
+    "Fill-Mask",
+    "distilbert/distilbert-base-uncased",
+    {
+      "net_profit": "29.430%",
+      "drawdown": "29.000%",
+      "sharpe": "1.586"
+    }
+  ],
+  [
+    "Fill-Mask",
+    "FacebookAI/roberta-base",
+    {
+      "net_profit": "-9.417%",
+      "drawdown": "16.700%",
+      "sharpe": "-1.296"
+    }
+  ],
+  [
+    "Fill-Mask",
+    "google-bert/bert-base-uncased",
+    {
+      "net_profit": "-9.417%",
+      "drawdown": "16.700%",
+      "sharpe": "-1.296"
+    }
+  ],
+  [
+    "Fill-Mask",
+    "microsoft/deberta-base",
+    "FAIL: backtest timed out"
+  ],
+  [
+    "Text Generation",
+    "openai-community/gpt2",
+    {
+      "net_profit": "19.558%",
+      "drawdown": "9.900%",
+      "sharpe": "1.952"
+    }
+  ],
+  [
+    "Text Generation",
+    "google/gemma-7b",
+    "FAIL: backtest timed out"
+  ],
+  [
+    "Text Generation",
+    "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
+    {
+      "net_profit": "N/A",
+      "drawdown": "N/A",
+      "sharpe": "N/A"
+    }
+  ],
+  [
+    "Chronos-Bolt",
+    "autogluon/chronos-bolt-base",
+    {
+      "net_profit": "7.246%",
+      "drawdown": "6.100%",
+      "sharpe": "0.686"
+    }
+  ]
+]
\ No newline at end of file
diff --git a/examples-check/run_model_variants.py b/examples-check/run_model_variants.py
new file mode 100644
index 0000000000..09da7bd9eb
--- /dev/null
+++ b/examples-check/run_model_variants.py
@@ -0,0 +1,376 @@
+"""Run backtests for all HuggingFace model variants and output a results table.
+
+Usage:
+    python examples-check/run_model_variants.py
+
+Credentials (checked in order):
+    1. Environment variables: DOCS_REGRESSION_TEST_USER_ID, DOCS_REGRESSION_TEST_USER_TOKEN
+    2. LEAN CLI credentials file: ~/.lean/credentials
+"""
+import sys
+import os
+import json
+import time
+import base64
+import hashlib
+from pathlib import Path
+
+try:
+    import requests
+except ImportError:
+    sys.exit("Missing dependency: pip install requests")
+
+try:
+    from bs4 import BeautifulSoup
+except ImportError:
+    sys.exit("Missing dependency: pip install beautifulsoup4")
+
+
+# ---------------------------------------------------------------------------
+# Credentials & API helpers
+# ---------------------------------------------------------------------------
+
+def _load_credentials():
+    user_id = os.environ.get("DOCS_REGRESSION_TEST_USER_ID", "")
+    user_token = os.environ.get("DOCS_REGRESSION_TEST_USER_TOKEN", "")
+    if user_id and user_token:
+        return user_id, user_token
+    lean_creds = Path.home() / ".lean" / "credentials"
+    if lean_creds.exists():
+        try:
+            creds = json.loads(lean_creds.read_text())
+            user_id = str(creds.get("user-id", ""))
+            user_token = creds.get("api-token", "")
+            if user_id and user_token:
+                return user_id, user_token
+        except (json.JSONDecodeError, KeyError):
+            pass
+    return "", ""
+
+
+BASE_API = "https://www.quantconnect.com/api/v2"
+USER_ID, USER_TOKEN = _load_credentials()
+PYTHON_IMPORTS = "from AlgorithmImports import *\n"
+MAX_RETRIES = 5
+POLL_INTERVAL = 10  # seconds between status polls
+BACKTEST_TIMEOUT = 1800  # seconds
+SLOW_THRESHOLD = 300  # seconds; placeholder backtests over this become skip-test
+# Set to a list of category names to skip (e.g. already tested ones)
+SKIP_CATEGORIES = ["Sentiment Analysis"]
+# Reuse an existing project instead of creating new ones (avoids 100/day limit).
+# Set to an integer project ID, or None to always create fresh projects.
+REUSE_PROJECT_ID = 29125823
+
+
+def _headers():
+    ts = str(int(time.time()))
+    hashed = hashlib.sha256(f"{USER_TOKEN}:{ts}".encode()).hexdigest()
+    auth = base64.b64encode(f"{USER_ID}:{hashed}".encode()).decode()
+    return {"Authorization": f"Basic {auth}", "Timestamp": ts}
+
+
+def api_post(endpoint, payload=None):
+    return requests.post(
+        f"{BASE_API}/{endpoint}",
+        headers=_headers(),
+        json=payload or {}
+    ).json()
+
+
+def clean_code(code):
+    return (code
+            .replace("&&", "&&")
+            .replace("<", "<")
+            .replace(">", ">"))
+
+
+# ---------------------------------------------------------------------------
+# HTML helpers
+# ---------------------------------------------------------------------------
+
+def mark_skip_test(file_path):
+    """Change 'testable' to 'skip-test' on the first matching example div."""
+    content = Path(file_path).read_text(encoding="utf-8")
+    updated = content.replace(
+        'class="section-example-container testable"',
+        'class="section-example-container skip-test"',
+        1  # only first occurrence
+    )
+    if updated != content:
+        Path(file_path).write_text(updated, encoding="utf-8")
+        print(f"  → Backtest exceeded {SLOW_THRESHOLD}s — marked skip-test: {Path(file_path).name}")
+
+
+# ---------------------------------------------------------------------------
+# Extract base code from HTML example file
+# ---------------------------------------------------------------------------
+
+def extract_python_code(file_path):
+    """Return the first testable Python QCAlgorithm code block in the file."""
+    html = Path(file_path).read_text(encoding="utf-8")
+    soup = BeautifulSoup(html, "html.parser")
+    for div in soup.find_all("div", class_="section-example-container"):
+        classes = div.get("class", [])
+        if "skip-test" in classes:
+            continue
+        for pre in div.find_all("pre", class_="python"):
+            code = pre.get_text()
+            if "(QCAlgorithm)" in code:
+                return clean_code(code)
+    raise ValueError(f"No testable Python QCAlgorithm block found in {file_path}")
+
+
+# ---------------------------------------------------------------------------
+# QC Cloud: create project, compile, backtest
+# ---------------------------------------------------------------------------
+
+def create_project_and_upload(code, label):
+    if REUSE_PROJECT_ID:
+        project_id = REUSE_PROJECT_ID
+    else:
+        ts = int(time.time())
+        name = f"DocTest/variants_{ts}_{label[:20]}"
+        resp = api_post("projects/create", {"name": name, "language": "Py"})
+        if not (resp.get("success") or resp.get("projects")):
+            raise RuntimeError(f"project create failed: {resp}")
+        project_id = resp["projects"][0]["projectId"]
+
+    full_code = PYTHON_IMPORTS + code
+    for _ in range(MAX_RETRIES):
+        r = api_post("files/update", {
+            "projectId": project_id,
+            "name": "main.py",
+            "content": full_code
+        })
+        if r.get("success"):
+            break
+        time.sleep(3)
+    else:
+        raise RuntimeError("file upload failed")
+
+    return project_id
+
+
+def compile_project(project_id):
+    resp = api_post("compile/create", {"projectId": project_id})
+    if not resp.get("success"):
+        raise RuntimeError(f"compile create failed: {resp}")
+    compile_id = resp.get("compileId") or resp.get("compile", {}).get("compileId")
+    if not compile_id:
+        raise RuntimeError(f"no compileId in response: {resp}")
+
+    deadline = time.time() + 300
+    while time.time() < deadline:
+        time.sleep(POLL_INTERVAL)
+        r = api_post("compile/read", {"projectId": project_id, "compileId": compile_id})
+        state = r.get("state") or r.get("compile", {}).get("state", "")
+        if state == "BuildSuccess":
+            return compile_id
+        if state == "BuildError":
+            logs = r.get("logs") or r.get("compile", {}).get("logs", [])
+            raise RuntimeError(f"compile error: {logs[-3:] if logs else r}")
+    raise RuntimeError("compile timed out")
+
+
+def run_backtest(project_id, compile_id, label):
+    resp = api_post("backtests/create", {
+        "projectId": project_id,
+        "compileId": compile_id,
+        "backtestName": label[:64]
+    })
+    if not resp.get("success"):
+        raise RuntimeError(f"backtest create failed: {resp}")
+    bt_id = resp["backtest"]["backtestId"]
+
+    deadline = time.time() + BACKTEST_TIMEOUT
+    while time.time() < deadline:
+        time.sleep(POLL_INTERVAL)
+        r = api_post("backtests/read", {"projectId": project_id, "backtestId": bt_id})
+        bt = r.get("backtest", {})
+        progress = bt.get("progress", 0)
+        completed = bt.get("completed", False)
+        if completed:
+            return bt
+        if bt.get("error"):
+            raise RuntimeError(f"backtest error: {bt['error']}")
+        print(f"    ... {int(progress*100)}% complete")
+    raise RuntimeError("backtest timed out")
+
+
+def extract_stats(bt):
+    # 'statistics' has the full set of metrics we need
+    stats = bt.get("statistics") or {}
+
+    def get(key, fallback="N/A"):
+        val = stats.get(key, fallback)
+        return val if val not in ("", None) else fallback
+
+    return {
+        "net_profit": get("Net Profit"),
+        "drawdown":   get("Drawdown"),
+        "sharpe":     get("Sharpe Ratio"),
+    }
+
+
+# ---------------------------------------------------------------------------
+# Model variants per category
+# ---------------------------------------------------------------------------
+
+BASE = Path(__file__).parent.parent
+
+CATEGORIES = [
+    {
+        "name": "Sentiment Analysis",
+        "file": BASE / "03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/06 Sentiment Analysis/99 Examples.html",
+        "placeholder": "mrm8488/distilroberta-finetuned-financial-news-sentiment-analysis",
+        "models": [
+            "mrm8488/distilroberta-finetuned-financial-news-sentiment-analysis",
+            "ahmedrachid/FinancialBERT-Sentiment-Analysis",
+            "AventIQ-AI/sentiment-analysis-for-stock-market-sentiment",
+            "bardsai/finance-sentiment-fr-base",
+            "cardiffnlp/twitter-roberta-base-sentiment-latest",
+            "nickmuchi/deberta-v3-base-finetuned-finance-text-classification",
+            "nickmuchi/distilroberta-finetuned-financial-text-classification",
+            "nickmuchi/sec-bert-finetuned-finance-classification",
+            "StephanAkkerman/FinTwitBERT-sentiment",
+        ],
+    },
+    {
+        "name": "Fill-Mask",
+        "file": BASE / "03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/07 Fill-Mask/99 Examples.html",
+        "placeholder": "distilbert/distilbert-base-uncased",
+        "models": [
+            "distilbert/distilbert-base-uncased",
+            "FacebookAI/roberta-base",
+            "google-bert/bert-base-uncased",
+            "microsoft/deberta-base",
+        ],
+    },
+    {
+        "name": "Text Generation",
+        "file": BASE / "03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/08 Text Generation/99 Examples.html",
+        "placeholder": "openai-community/gpt2",
+        "models": [
+            "openai-community/gpt2",
+            "google/gemma-7b",
+            "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
+        ],
+    },
+    {
+        "name": "Chronos-Bolt",
+        "file": BASE / "03 Writing Algorithms/31 Machine Learning/04 Hugging Face/02 Popular Models/12 Chronos-Bolt/99 Examples.html",
+        "placeholder": "autogluon/chronos-bolt-base",
+        "models": [
+            "autogluon/chronos-bolt-base",
+        ],
+    },
+]
+
+
+# ---------------------------------------------------------------------------
+# Main
+# ---------------------------------------------------------------------------
+
+def main():
+    if not USER_ID or not USER_TOKEN:
+        sys.exit(
+            "Error: Set DOCS_REGRESSION_TEST_USER_ID and "
+            "DOCS_REGRESSION_TEST_USER_TOKEN environment variables."
+        )
+
+    resp = api_post("authenticate")
+    if not resp.get("success"):
+        sys.exit("API authentication failed. Check your credentials.")
+    print("API authentication successful.\n")
+
+    results = []  # list of (category, model, stats_dict | error_str)
+
+    for cat in CATEGORIES:
+        if cat["name"] in SKIP_CATEGORIES:
+            print(f"\nSkipping: {cat['name']}")
+            continue
+        print(f"\n{'='*60}")
+        print(f"Category: {cat['name']}")
+        print(f"{'='*60}")
+
+        try:
+            base_code = extract_python_code(str(cat["file"]))
+        except Exception as e:
+            print(f"  ERROR reading code: {e}")
+            for model in cat["models"]:
+                results.append((cat["name"], model, f"code read error: {e}"))
+            continue
+
+        for model in cat["models"]:
+            label = f"{cat['name'][:8]}_{model.split('/')[-1][:20]}"
+            print(f"\n  Model: {model}")
+            try:
+                code = base_code.replace(cat["placeholder"], model)
+
+                print(f"  Creating project...")
+                project_id = create_project_and_upload(code, label)
+
+                print(f"  Compiling (project {project_id})...")
+                compile_id = compile_project(project_id)
+
+                print(f"  Running backtest...")
+                bt_start = time.time()
+                bt = run_backtest(project_id, compile_id, label)
+                bt_elapsed = time.time() - bt_start
+
+                if model == cat["placeholder"] and bt_elapsed > SLOW_THRESHOLD:
+                    mark_skip_test(str(cat["file"]))
+
+                stats = extract_stats(bt)
+                print(f"  PASS — net profit={stats['net_profit']}  "
+                      f"drawdown={stats['drawdown']}  sharpe={stats['sharpe']}  "
+                      f"({int(bt_elapsed)}s)")
+                results.append((cat["name"], model, stats))
+
+            except Exception as e:
+                import traceback
+                traceback.print_exc()
+                print(f"  FAIL — {e}")
+                results.append((cat["name"], model, f"FAIL: {e}"))
+
+    # -----------------------------------------------------------------------
+    # Print results table
+    # -----------------------------------------------------------------------
+    print("\n\n" + "="*80)
+    print("RESULTS TABLE (Markdown)")
+    print("="*80)
+    print()
+
+    # Group by category
+    categories_seen = []
+    rows_by_cat = {}
+    for cat_name, model, stats in results:
+        if cat_name not in rows_by_cat:
+            rows_by_cat[cat_name] = []
+            categories_seen.append(cat_name)
+        rows_by_cat[cat_name].append((model, stats))
+
+    for cat_name in categories_seen:
+        rows = rows_by_cat[cat_name]
+        print(f"### {cat_name}\n")
+        print("| Model | Net Profit | Drawdown | Sharpe Ratio |")
+        print("|-------|-----------|----------|--------------|")
+        for model, stats in rows:
+            if isinstance(stats, dict):
+                np_ = stats['net_profit']
+                dd  = stats['drawdown']
+                sr  = stats['sharpe']
+                print(f"| `{model}` | {np_} | {dd} | {sr} |")
+            else:
+                print(f"| `{model}` | {stats} | — | — |")
+        print()
+
+    # Also dump raw JSON for debugging
+    output_path = Path(__file__).parent / "model_variant_results.json"
+    with open(output_path, "w") as f:
+        json.dump(results, f, indent=2, default=str)
+    print(f"Raw results saved to {output_path}")
+
+
+if __name__ == "__main__":
+    main()