code: def long_short_backtest(
      pred,
      topk=50,
      deal_price=None,
      shift=1,
      open_cost=0,
      close_cost=0,
      trade_unit=None,
      limit_threshold=None,
      min_cost=5,
      subscribe_fields=[],
      extract_codes=False,
  ):
      """
      A backtest for long-short strategy
  
      :param pred:        The trading signal produced on day `T`.
      :param topk:       The short topk securities and long topk securities.
      :param deal_price:  The price to deal the trading.
      :param shift:       Whether to shift prediction by one day.  The trading day will be T+1 if shift==1.
      :param open_cost:   open transaction cost.
      :param close_cost:  close transaction cost.
      :param trade_unit:  100 for China A.
      :param limit_threshold: limit move 0.1 (10%) for example, long and short with same limit.
      :param min_cost:    min transaction cost.
      :param subscribe_fields: subscribe fields.
      :param extract_codes:  bool.
                         will we pass the codes extracted from the pred to the exchange.
                         NOTE: This will be faster with offline qlib.
      :return:            The result of backtest, it is represented by a dict.
                          { "long": long_returns(excess),
                          "short": short_returns(excess),
                          "long_short": long_short_returns}
      """
      if get_level_index(pred, level="datetime") == 1:
          pred = pred.swaplevel().sort_index()
  
      if trade_unit is None:
          trade_unit = C.trade_unit
      if limit_threshold is None:
          limit_threshold = C.limit_threshold
      if deal_price is None:
          deal_price = C.deal_price
      if deal_price[0] != "$":
          deal_price = "$" + deal_price
  
      subscribe_fields = subscribe_fields.copy()
      profit_str = f"Ref({deal_price}, -1)/{deal_price} - 1"
      subscribe_fields.append(profit_str)
  
      trade_exchange = get_exchange(
          pred=pred,
          deal_price=deal_price,
          subscribe_fields=subscribe_fields,
          limit_threshold=limit_threshold,
          open_cost=open_cost,
          close_cost=close_cost,
          min_cost=min_cost,
          trade_unit=trade_unit,
          extract_codes=extract_codes,
          shift=shift,
      )
  
      _pred_dates = pred.index.get_level_values(level="datetime")
      predict_dates = D.calendar(
          start_time=_pred_dates.min(), end_time=_pred_dates.max()
      )
      trade_dates = np.append(
          predict_dates[shift:],
          get_date_range(
              predict_dates[-1], left_shift=1, right_shift=shift
          ),
      )
  
      long_returns = {}
      short_returns = {}
      ls_returns = {}
  
      for pdate, date in zip(predict_dates, trade_dates):
          score = pred.loc(axis=0)[pdate, :]
          score = score.reset_index().sort_values(
              by="score", ascending=False
          )
  
          long_stocks = list(score.iloc[:topk]["instrument"])
          short_stocks = list(score.iloc[-topk:]["instrument"])
  
          score = score.set_index(
              ["datetime", "instrument"]
          ).sort_index()
  
          long_profit = []
          short_profit = []
          all_profit = []
  
          for stock in long_stocks:
              if not trade_exchange.is_stock_tradable(
                  stock_id=stock, trade_date=date
              ):
                  continue
              profit = trade_exchange.get_quote_info(
                  stock_id=stock,
                  start_time=date,
                  end_time=date,
                  field=profit_str,
              )
              if np.isnan(profit):
                  long_profit.append(0)
              else:
                  long_profit.append(profit)
  
          for stock in short_stocks:
              if not trade_exchange.is_stock_tradable(
                  stock_id=stock, trade_date=date
              ):
                  continue
              profit = trade_exchange.get_quote_info(
                  stock_id=stock,
                  start_time=date,
                  end_time=date,
                  field=profit_str,
              )
              if np.isnan(profit):
                  short_profit.append(0)
              else:
                  short_profit.append(profit * -1)
  
          for stock in list(
              score.loc(axis=0)[pdate, :].index.get_level_values(
                  level=0
              )
          ):
              # exclude the suspend stock
              if trade_exchange.check_stock_suspended(
                  stock_id=stock, trade_date=date
              ):
                  continue
              profit = trade_exchange.get_quote_info(
                  stock_id=stock,
                  start_time=date,
                  end_time=date,
                  field=profit_str,
              )
              if np.isnan(profit):
                  all_profit.append(0)
              else:
                  all_profit.append(profit)
  
          long_returns[date] = np.mean(long_profit) - np.mean(
              all_profit
          )
          short_returns[date] = np.mean(short_profit) + np.mean(
              all_profit
          )
          ls_returns[date] = np.mean(short_profit) + np.mean(
              long_profit
          )
  
      return dict(
          zip(
              ["long", "short", "long_short"],
              map(pd.Series, [long_returns, short_returns, ls_returns]),
          )
      )
  
file_path: qlib/qlib/contrib/evaluate.py
imports: from __future__ import division
  from __future__ import print_function
  import numpy
  import pandas
  import warnings
  from typing import Union
  from ..log import get_module_logger
  from ..utils import get_date_range
  from ..utils.resam import Freq
  from ..strategy.base import BaseStrategy
  from ..backtest import get_exchange, position, backtest, executor
  from ..data import D
  from ..config import C
  from ..data.dataset.utils import get_level_index
label_desc: Use image node_id 4 for calling a global function with example usage: long_short_backtest(pred, topk, deal_price, shift, open_cost, close_cost, trade_unit, limit_threshold, min_cost, subscribe_fields, extract_codes) and returns: dict