class_docstr: Hyperparameter tuning of SB3 agents using Optuna
  
  Attributes
  ----------
    env_train: Training environment for SB3
    model_name: str
    env_trade: testing environment
    logging_callback: callback for tuning
    total_timesteps: int
    n_trials: number of hyperparameter configurations
  
  Note:
    The default sampler and pruner are used are
    Tree Parzen Estimator and Hyperband Scheduler
    respectively.
code: def __init__(
      self,
      env_train,
      model_name: str,
      env_trade,
      logging_callback,
      total_timesteps: int = 50000,
      n_trials: int = 30,
  ):
      self.env_train = env_train
      self.agent = DRLAgent(env=env_train)
      self.model_name = model_name
      self.env_trade = env_trade
      self.total_timesteps = total_timesteps
      self.n_trials = n_trials
      self.logging_callback = logging_callback
      self.MODELS = {
          "a2c": A2C,
          "ddpg": DDPG,
          "td3": TD3,
          "sac": SAC,
          "ppo": PPO,
      }
  
      check_and_make_directories(
          [
              config.DATA_SAVE_DIR,
              config.TRAINED_MODEL_DIR,
              config.TENSORBOARD_LOG_DIR,
              config.RESULTS_DIR,
          ]
      )
  
imports: from __future__ import annotations
  import datetime
  import joblib
  import optuna
  import pandas
  from stable_baselines3 import A2C
  from stable_baselines3 import DDPG
  from stable_baselines3 import PPO
  from stable_baselines3 import SAC
  from stable_baselines3 import TD3
  import finrl.agents.stablebaselines3.hyperparams_opt
  from finrl import config
  from finrl.agents.stablebaselines3.models import DRLAgent
  from finrl.main import check_and_make_directories
  from finrl.plot import backtest_stats
label_desc: Use image node_id 1 to create a new TuneSB3Optuna object  with example: obj = TuneSB3Optuna(env_train, model_name, env_trade, logging_callback, total_timesteps, n_trials)