code: def run(self, h, recalculate=False):
          
  
          data = self.data[-h:] 
          predictions = self._model_predict_is(h, recalculate=recalculate).values
          weights = np.zeros((h, len(self.model_list)))
          normalized_weights = np.zeros((h, len(self.model_list)))
          ensemble_prediction = np.zeros(h)
          
          for t in range(h):
              if t == 0:
                  weights[t,:] = 100000
                  ensemble_prediction[t] = np.dot(weights[t,:]/weights[t,:].sum(), predictions[t,:])
                  weights[t,:] = weights[t,:]*np.exp(-self.learning_rate*self.loss_type(data[t], predictions[t,:]))
                  normalized_weights[t,:] = weights[t,:]/weights[t,:].sum()
              else:
                  ensemble_prediction[t] = np.dot(weights[t-1,:]/weights[t-1,:].sum(), predictions[t,:])
                  weights[t,:] = weights[t-1,:]*np.exp(-self.learning_rate*self.loss_type(data[t], predictions[t,:]))
                  normalized_weights[t,:] = weights[t,:]/weights[t,:].sum()
  
          return normalized_weights, self._construct_losses(data, predictions, ensemble_prediction), ensemble_prediction
docs: Run the aggregating algorithm 
          
          Parameters
          ----------
          h : int
              How many steps to run the aggregating algorithm on 
  
          recalculate: boolean
              Whether to recalculate the predictions or not
  
          Returns
          ----------
          - np.ndarray of normalized weights, np.ndarray of losses for each model