# Falcon: Introduction to notebook quickstarters

**URL:** https://forum.crunchdao.com/t/falcon-introduction-to-notebook-quickstarters/1060
**Category:** Falcon: The Collective Pricing Engine
**Created:** [October 21, 2025, 3:52pm UTC](https://forum.crunchdao.com/t/falcon-introduction-to-notebook-quickstarters/1060 "2025-10-21T15:52:18Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![tarandros](https://forum.crunchdao.com/user_avatar/forum.crunchdao.com/tarandros/32/438_2.png) [@tarandros](https://forum.crunchdao.com/u/tarandros)
#### Post date: [October 21, 2025, 3:52pm UTC](https://forum.crunchdao.com/t/falcon-introduction-to-notebook-quickstarters/1060/1 "2025-10-21T15:52:18Z")

</div>

# **Falcon: Introduction to notebook quickstarters**

[Falcon](https://hub.crunchdao.com/competitions/falcon) is a live simulation where your model plays the role of a _ **tracker** _, trying to follow the movement of a **dove** in flight. At every tick, you receive partial observations and must predict where the dove will be next (in `HORIZON` secondes).

The goal: **Maximize likelihood** — the score measuring how well your predicted probability distribution matches the dove’s true future positions. The higher the likelihood, the better calibrated your model.

**Visualize the challenge:**

The following animated graph shows the **dove’s true (observed) locations** and the **future locations** on an `Horizon` of 3 secondes.

 ![image](https://forum.crunchdao.com/uploads/default/original/1X/facc3b21df8cb7eedd93187fde4fa0bbb30cd431.png)

* * *

## **How the Game Works**

- You receive updates ( **ticks** ) containing the dove’s latest location.

- Your tracker updates its internal model (`tick()`).

- Then you return a **probability density prediction** (`predict()`), not just a point estimate, representing where you believe the dove will be in `HORIZON` seconds.

**Example output:**

```json
{
    "type": "mixture",
    "components": [
        {
        "density": {"type": "builtin", "name": "norm", 
                    "params": {"loc": 3.7, "scale": 0.8}},
        "weight": 0.6
        },
        {
        "density": {"type": "builtin", "name": "cauchy", 
                    "params": {"loc": 3.5, "scale": 1.2}},
        "weight": 0.4
        }
    ]
}

```

The leaderboard evaluates **log-likelihood** of your predicted distribution against real dove locations, so both **accuracy** and **uncertainty estimation** matter.

**Live graph example (3 secondes Horizon):**

![falcongame_animation_2_half](https://forum.crunchdao.com/uploads/default/original/1X/6d1a48c5a2dffdb799c96cbde671ceb9ecd82556.gif)

You can explore all available distributions in the [`densitypdf`](https://github.com/microprediction/densitypdf/blob/main/densitypdf/builtin/builtindensitypdf.py) package.

- [Dataset Description](https://hub.crunchdao.com/competitions/falcon#data): Learn the data structure

- [Game Rules](https://hub.crunchdao.com/competitions/falcon#game-rules): Understand how the game works and scoring

- [Probabilistic forecasting](https://hub.crunchdao.com/competitions/falcon#probabilistic-forecast): Explanation of probabilistic forecasting

**Probabilistic forecasting can be handled through various approaches, including:**

- **Variance forecasters**
- **Quantile forecasters**
- **Interval forecasters**
- **Distribution forecasters**

* * *

## **Quickstarters: From Baselines to Smarter Trackers**

Now that you understand the game mechanics, let’s explore some ready-to-use **quickstarter trackers**.  
These templates will help you get started quickly with probabilistic forecasting and test ideas.

* * *

### **1. Naive Tracker**

The **NaiveTracker** is the simplest strategy — it predicts that the dove will stay near its last observed location.  
This tracker does **not learn** from past data, but it’s perfect for testing your setup and understanding the prediction interface. It uses the most recent observation as the mean of a Gaussian distribution and the scale (uncertainty) is fixed:

```python
from birdgame.trackers.trackerbase import TrackerBase
from birdgame import HORIZON

class NaiveTracker(TrackerBase):
    def __init__ (self, horizon=HORIZON):
        super(). __init__ (horizon)
        self.current_x = None

    def tick(self, payload, performance_metrics=None):
        self.current_x = payload['dove_location']
        t = payload["time"]

    def predict(self):
        return {
            "type": "mixture",
            "components": [{
                "density": {"type": "builtin", "name": "norm", 
                     "params": {"loc": self.current_x, "scale": 0.01}},
                "weight": 1
            }]
        }

```

> **This code is sufficient for submission to the challenge**. A class that inherits from `TrackerBase`, processes the payload in `tick()` and returns a probability density prediction in `predict()`.
> 
> You just need to copy it into a notebook and submit it on the [Falcon submit a notebook](https://hub.crunchdao.com/competitions/falcon/submit/notebook) section. You can also copy it into a python file and submit it on the [Falcon submit files](https://hub.crunchdao.com/competitions/falcon/submit/files) section

* * *

### **2. EWMA Variance and Mixture of Gaussians (variance forecaster)**

Full quickstarter notebook: [EWMA Variance Tracker](https://github.com/microprediction/birdgame/blob/main/birdgame/examples/quickstarters/ewma_var.ipynb)

A method for tracking variance over time while giving more importance to recent observations using an exponential decay factor.

The **EMWAVarTracker** fits a mixture of two Gaussian distributions to model both typical fluctuations and extreme moves.:

- **Core distribution** — captures regular variance

- **Tail distribution** — captures extreme deviations

It uses **EWMA (Exponentially Weighted Moving Average)** to update variance dynamically.

**Minimal example:**

```python
from birdgame.stats.fewvar import FEWVar

class EMWAVarTracker(TrackerBase):
    def __init__ (self, horizon=HORIZON):
        super(). __init__ (horizon)
        self.current_x = None
        self.ewa_dx_core = FEWVar(fading_factor=0.0001)
        self.ewa_dx_tail = FEWVar(fading_factor=0.0001)

    def tick(self, payload, performance_metrics=None):
        x = payload['dove_location']
        # Adds a new value to the quarantine list.
        # The value will become available for prediction processing 
        # at `time + self.horizon`.
        self.add_to_quarantine(payload['time'], x)
        # Returns the most recent valid data point from quarantine,
        # if available.
        prev_x = self.pop_from_quarantine(payload['time'])
        if prev_x is not None:
            self.ewa_dx_core.update(np.clip(x-prev_x, -2, 2))
            self.ewa_dx_tail.update(2*(x-prev_x))
        self.current_x = x

    def predict(self):
        if self.ewa_dx_core.get() == 0.0:
            return None # warmup period
        return {
            "type": "mixture",
            "components": [
                {"density": {"type": "builtin", "name": "norm", 
    "params": {"loc": self.current_x, 
             "scale": math.sqrt(self.ewa_dx_core.get())}}, 
    "weight": 0.95},
                {"density": {"type": "builtin", "name": "norm", 
    "params": {"loc": self.current_x, 
             "scale": math.sqrt(self.ewa_dx_tail.get())}}, 
    "weight": 0.05}
            ]
        }

```

> You can return `None` during your tracker’s warmup period — no wealth is at stake during this time.

* * *

### **3. Online Quantile Linear Regression (quantile forecaster)**

Full quickstarter notebook: [Quantile Linear Regression](https://github.com/microprediction/birdgame/blob/main/birdgame/examples/quickstarters/quantile_regression_river.ipynb)

The **QuantileRegressionRiverTracker** uses **online quantile regression** to track the dove location. Quantile forecasting enables the creation of prediction intervals by estimating lower and upper quantiles.

**Minimal example:**

```python
from river import linear_model, preprocessing, optim

class QuantileRegressionRiverTracker(TrackerBase):
    def __init__ (self, horizon=HORIZON):
        super(). __init__ (horizon)
        self.current_x = None
        self.models = {}
        for alpha in [0.05, 0.5, 0.95]:
            scale = preprocessing.StandardScaler()
            learn = linear_model.LinearRegression(
                intercept_lr=0,
                optimizer=optim.SGD(0.005),
                loss=optim.losses.Quantile(alpha=alpha)
            )
            model = scale | learn
            model = preprocessing.TargetStandardScaler(regressor=model)
            self.models[f"q {alpha:.2f}"] = model

    def tick(self, payload, performance_metrics=None):
        x = payload['dove_location']
        self.add_to_quarantine(payload['time'], x)
        prev_x = self.pop_from_quarantine(payload['time'])
        if prev_x is not None:
            for m in self.models.values():
                m.learn_one({"x": prev_x}, x)
        self.current_x = x

    def predict(self):
        x_mean = self.models["q 0.50"].predict_one({"x": self.current_x})
        y_lower = self.models["q 0.05"].predict_one({"x": self.current_x})
        y_upper = self.models["q 0.95"].predict_one({"x": self.current_x})
        scale = max(abs(y_upper - y_lower)/3.29, 1e-6)
        return {
            "type": "mixture",
            "components": [{"density": {"type": "builtin", "name": "norm",
             "params": {"loc": x_mean, "scale": scale}}, "weight": 1}]
        }

```

It predicts multiple quantiles (5%, 50%, 95%) to capture uncertainty dynamically,  
with the scale computed as `(y_upper - y_lower) / (norm.ppf(q_upper) - norm.ppf(q_lower))`.

* * *

### **4. Automatic Exponential Smoothing (variance forecaster)**

Full quickstarter notebook: [AutoETS](https://github.com/microprediction/birdgame/blob/main/birdgame/examples/quickstarters/auto_ets_sktime.ipynb)

**AutoETS** (Auto Exponential Smoothing) from `sktime` is an automatic forecasting method that applies exponential smoothing to time series data with trend and seasonality.

**Minimal example:**

```python
from sktime.forecasting.ets import AutoETS

class AutoETSsktimeTracker(TrackerBase):
    def __init__ (self, horizon=HORIZON):
        super(). __init__ (horizon)
        self.current_x = None
        self.last_observed_data = []
        self.forecaster = AutoETS(auto=True, sp=1,
                                  information_criterion="aic")
        self.scale = 1e-6
        self.num_data_points_max = 5
        self.prev_t = 0

    def tick(self, payload, performance_metrics=None):
        x = payload["dove_location"]
        t = payload["time"]
        self.current_x = x

        # Collect and process observations only at horizon-based intervals
        if t > self.prev_t + self.horizon:
            self.last_observed_data.append(x)
            self.prev_t = t
            if len(self.last_observed_data) >= self.num_data_points_max:
                y = np.array(
                      self.last_observed_data[-self.num_data_points_max:]
                     )
                self.forecaster.fit(y)
                var = self.forecaster.predict_var(fh=[1])
                self.scale = np.sqrt(var.values.flatten()[-1])

                # Update last observed data (to limit memory usage 
                # as it will be run on continuous live data)
                self.last_observed_data = self.last_observed_data[-
                                          (self.num_data_points_max + 2):]

    def predict(self):
        if len(self.last_observed_data) < self.num_data_points_max:
            return None # warmup period
        return {
            "type": "mixture",
            "components": [{"density": {"type": "builtin", "name": "norm",
              "params": {"loc": self.current_x, "scale": self.scale}},
              "weight": 1}]
        }

```

> **Performance tip:** Inference must be completed in **under 50 ms**.  
> In the quickstarter notebook, you will find an example of **asynchronous retraining** to avoid blocking predictions while updating the model in the background.
> 
> **Memory tip:** The tracker keeps only the most recent observations to **limit memory usage** , which is important for continuous live data streams.

* * *

### **5. Natural Gradient Boosted (distribution forecaster)**

Full quickstarter notebook: [NGBoost](https://github.com/microprediction/birdgame/blob/main/birdgame/examples/quickstarters/ngboost.ipynb)

**NGBoost** (Natural Gradient Boosting) is a method for probabilistic regression that extends gradient boosting to predict full probability distributions instead of just point estimates. It predicts a **Gaussian distribution** , capturing both mean and uncertainty:

- introduction: [https://stanfordmlgroup.github.io/projects/ngboost/](https://stanfordmlgroup.github.io/projects/ngboost/)

- paper: [https://arxiv.org/pdf/1910.03225](https://arxiv.org/pdf/1910.03225)

- github: [https://github.com/stanfordmlgroup/ngboost](https://github.com/stanfordmlgroup/ngboost)

- user guide: [https://stanfordmlgroup.github.io/ngboost/intro.html](https://stanfordmlgroup.github.io/ngboost/intro.html)

- **guide to add new distribution target and scoring** : [https://stanfordmlgroup.github.io/ngboost/5-dev.html](https://stanfordmlgroup.github.io/ngboost/5-dev.html)

### 6. Run the Wealth Distribution Simulation with Multiple Trackers

Full quickstarter notebook: [Wealth Distribution](https://github.com/microprediction/birdgame/blob/main/birdgame/examples/quickstarters/wealth_distribution.ipynb)

A notebook is available to **simulate the Falcon Wealth Game** using multiple trackers at once.  
This simulation allows you to observe how different prediction models interact under shared conditions, competing for the same reward pot based on their likelihood performance.

Each tracker receives an initial **wealth allocation** and invests a small fraction of it at every tick.  
The reward pot is then redistributed proportionally to each model’s **likelihood score** , reflecting both predictive accuracy and model diversity.

You can easily include any tracker (e.g:`EMWAVarTracker`, `AutoETSsktimeTracker`, `NGBoostTracker`, `QuantileRegressionRiverTracker`) and watch how wealth evolves over time.

Wealth distribution simulation on 3 trackers:

 ![image](https://forum.crunchdao.com/uploads/default/original/1X/5484ad3ae93f0dcdd1dce7fa968bdf1dc2e56885.png)

### **NOTE:**

At every tick, you receive the dove’s current location along with additional information:

`{'time': 53952.14900016785, 'falcon_location': 2200.15, 'dove_location': 2200.16, 'falcon_id': 72, 'falcon_wingspan': 0.2014}`

This graph shows the **dove’s known location** along with **multiple falcon IDs** :

 ![falcons](https://forum.crunchdao.com/uploads/default/original/1X/41965dd5d1be88f9434e3093541332593173071f.png)

> The falcon locations are shown as colored dots on the figure above. Some falcons may provide useful information as to (track) the future location of the dove, or the uncertainty of the same, whereas others may not. Their utility, or otherwise, is for you to determine.

## **🚀 Submitting Your Tracker to the Falcon CrunchDAO Platform**

Once you’ve explored or customized one of the [Quickstarter notebooks](https://github.com/microprediction/birdgame/tree/main/birdgame/examples/quickstarters), submitting your tracker is straightforward.

1. **Open a Quickstarter Notebook**

2. **Customize (Optional)**  
You can adjust:

3. **Submit to the Platform**

You can also check the [documentation](https://docs.crunchdao.com/real-time-competitions/participate).

Your tracker will then compete live in the Birdgame simulation, with real-time log-likelihood scores displayed on the leaderboard.
