class_docstr: Portfolio Optimizer for Enhanced Indexing
  
  Notations:
      w0: current holding weights
      wb: benchmark weight
      r: expected return
      F: factor exposure
      cov_b: factor covariance
      var_u: residual variance (diagonal)
      lamb: risk aversion parameter
      delta: total turnover limit
      b_dev: benchmark deviation limit
      f_dev: factor deviation limit
  
  Also denote:
      d = w - wb: benchmark deviation
      v = d @ F: factor deviation
  
  The optimization problem for enhanced indexing:
      max_w  d @ r - lamb * (v @ cov_b @ v + var_u @ d**2)
      s.t.   w >= 0
             sum(w) == 1
             sum(|w - w0|) <= delta
             d >= -b_dev
             d <= b_dev
             v >= -f_dev
             v <= f_dev
docstr: Args:
      lamb (float): risk aversion parameter (larger `lamb` means more focus on risk)
      delta (float): total turnover limit
      b_dev (float): benchmark deviation limit
      f_dev (list): factor deviation limit
      scale_return (bool): whether scale return to match estimated volatility
      epsilon (float): minimum weight
      solver_kwargs (dict): kwargs for cvxpy solver
docstr_tok: ["Args",":","lamb","(","float",")",":","risk","aversion","parameter","(","larger","`","lamb","`","means","more","focus","on","risk",")","delta","(","float",")",":","total","turnover","limit","b_dev","(","float",")",":","benchmark","deviation","limit","f_dev","(","list",")",":","factor","deviation","limit","scale_return","(","bool",")",":","whether","scale","return","to","match","estimated","volatility","epsilon","(","float",")",":","minimum","weight","solver_kwargs","(","dict",")",":","kwargs","for","cvxpy","solver"]
code: def __init__(
      self,
      lamb: float = 1,
      delta: Optional[float] = 0.2,
      b_dev: Optional[float] = 0.01,
      f_dev: Optional[Union[List[float], np.ndarray]] = None,
      scale_return: bool = True,
      epsilon: float = 5e-5,
      solver_kwargs: Optional[Dict[str, Any]] = {},
  ):
      """
      Args:
          lamb (float): risk aversion parameter (larger `lamb` means more focus on risk)
          delta (float): total turnover limit
          b_dev (float): benchmark deviation limit
          f_dev (list): factor deviation limit
          scale_return (bool): whether scale return to match estimated volatility
          epsilon (float): minimum weight
          solver_kwargs (dict): kwargs for cvxpy solver
      """
  
      assert (
          lamb >= 0
      ), "risk aversion parameter `lamb` should be positive"
      self.lamb = lamb
  
      assert delta >= 0, "turnover limit `delta` should be positive"
      self.delta = delta
  
      assert (
          b_dev is None or b_dev >= 0
      ), "benchmark deviation limit `b_dev` should be positive"
      self.b_dev = b_dev
  
      if isinstance(f_dev, float):
          assert (
              f_dev >= 0
          ), "factor deviation limit `f_dev` should be positive"
      elif f_dev is not None:
          f_dev = np.array(f_dev)
          assert all(
              f_dev >= 0
          ), "factor deviation limit `f_dev` should be positive"
      self.f_dev = f_dev
  
      self.scale_return = scale_return
      self.epsilon = epsilon
      self.solver_kwargs = solver_kwargs
  
file_path: qlib/qlib/contrib/strategy/optimizer/enhanced_indexing.py
imports: import numpy
  import cvxpy
  from typing import Union, Optional, Dict, Any, List
  from qlib.log import get_module_logger
  from .base import BaseOptimizer
label_desc: Use image node_id 1 to create a new EnhancedIndexingOptimizer object from inherited base classes: BaseOptimizer with example: obj = EnhancedIndexingOptimizer(lamb, delta, b_dev, f_dev, scale_return, epsilon, solver_kwargs)