Skip to main content

The Condor Challenge

Condor is a financial prediction competition where participants build models to forecast probability distributions of asset returns over multiple time horizons. Unlike traditional point predictions (“I think the price will be $100”), Condor asks:
“What is the probability distribution of returns over the next N hours?”
This captures the full uncertainty in predictions and allows for more sophisticated scoring.

The TrackerBase Interface

All participant models must implement the TrackerBase class, which defines two core methods:
class TrackerBase:
    def tick(self, data: dict) -> None:
        """
        Receive latest market data.

        Called whenever new market data is available.
        Models use this to update their internal state.

        Args:
            data: Dictionary containing market prices, features, timestamps
                  Example:
                  {
                      "timestamp": "2024-01-15T10:30:00Z",
                      "prices": {
                          "BTC-USD": 45000.0,
                          "ETH-USD": 2500.0
                      },
                      "features": {...}
                  }
        """
        raise NotImplementedError

    def predict(
        self,
        asset: str,
        horizon: int,
        step: int
    ) -> dict:
        """
        Generate a probability distribution prediction.

        Args:
            asset: Asset code (e.g., "BTC-USD")
            horizon: Prediction timeframe in hours (e.g., 1, 4, 24)
            step: Current prediction step/round

        Returns:
            Dictionary containing a probability distribution:
            {
                "distribution": {
                    "-0.05": 0.1,  # 10% prob of -5% return
                    "0.00": 0.6,   # 60% prob of 0% return
                    "0.05": 0.3    # 30% prob of +5% return
                }
            }
        """
        raise NotImplementedError

Understanding Tick vs Predict

Tick: Receiving Market Data

The tick() method is called whenever new market data arrives: When it’s called:
  • Typically every minute or when new data is available
  • Before any prediction request
  • Can be called multiple times before a predict
What it does:
  • Updates model’s internal state with latest data
  • Processes features, updates indicators
  • Prepares model for next prediction
Important notes:
  • Returns nothing (None)
  • Should be fast and non-blocking
  • Cannot fail - must handle errors gracefully
Example implementation:
class MyTracker(TrackerBase):
    def __init__(self):
        self.price_history = []
        self.last_price = None

    def tick(self, data):
        try:
            timestamp = data["timestamp"]
            prices = data["prices"]

            # Update internal state
            for asset, price in prices.items():
                self.price_history.append({
                    "timestamp": timestamp,
                    "asset": asset,
                    "price": price
                })

            # Keep only recent history
            self.price_history = self.price_history[-1000:]

        except Exception as e:
            # Never let tick fail completely
            print(f"Error in tick: {e}")
Participants on the CrunchDAO Hub will:
  1. Install the package
  2. Import and inherit from TrackerBase
  3. Implement tick() and predict()
  4. Submit their model on the CrunchDAO Hub

Next Steps

Now that you understand the prediction task interface, let’s explore how participants implement models.

Crunch Node Architecture

Learn how the three-worker architecture manages models, scoring, and reporting.