code: def handle_data(context, data):
      log.info("handling bar {}".format(data.current_dt))
  
      buying_price = data.current(
          context.trading_pairs[context.buying_exchange], "price"
      )
  
      log.info(
          "price on buying exchange {exchange}: {price}".format(
              exchange=context.buying_exchange.name.upper(),
              price=buying_price,
          )
      )
  
      selling_price = data.current(
          context.trading_pairs[context.selling_exchange], "price"
      )
  
      log.info(
          "price on selling exchange {exchange}: {price}".format(
              exchange=context.selling_exchange.name.upper(),
              price=selling_price,
          )
      )
  
      # If for example,
      #   selling price = 50
      #   buying price = 25
      #   expected gap = 1
  
      # If follows that,
      #   selling price - buying price / buying price
      #   50 - 25 / 25 = 1
      gap = (selling_price - buying_price) / buying_price
      log.info(
          "the price gap: {gap} ({gap_percent}%)".format(
              gap=gap, gap_percent=gap * 100
          )
      )
      record(
          buying_price=buying_price,
          selling_price=selling_price,
          gap=gap,
      )
  
      # Waiting for orders to close before initiating new ones
      for exchange in context.trading_pairs:
          asset = context.trading_pairs[exchange]
  
          if asset in context.blotter.open_orders:
              log.info(
                  "found {order_count} open orders on {exchange_name} "
                  "skipping bar until all open orders execute".format(
                      order_count=len(
                          context.blotter.open_orders(asset)
                      ),
                      exchange_name=exchange.name,
                  )
              )
              return
  
      # Consider the least ambitious entry point first
      # Override of wider gap is found
      entry_points = sorted(
          context.entry_points,
          key=lambda point: point["gap"],
      )
  
      buy_amount = None
      for entry_point in entry_points:
          if gap > entry_point["gap"]:
              buy_amount = entry_point["amount"]
  
      if buy_amount:
          log.info(
              "found buy trigger for amount: {}".format(buy_amount)
          )
          place_orders(
              context=context,
              amount=buy_amount,
              buying_price=buying_price,
              selling_price=selling_price,
              action="enter",
          )
  
      else:
          # Consider the narrowest exit gap first
          # Override of wider gap is found
          exit_points = sorted(
              context.exit_points,
              key=lambda point: point["gap"],
              reverse=True,
          )
  
          sell_amount = None
          for exit_point in exit_points:
              if gap < exit_point["gap"]:
                  sell_amount = exit_point["amount"]
  
          if sell_amount:
              log.info(
                  "found sell trigger for amount: {}".format(
                      sell_amount
                  )
              )
              place_orders(
                  context=context,
                  amount=sell_amount,
                  buying_price=buying_price,
                  selling_price=selling_price,
                  action="exit",
              )
  
file_path: catalyst/catalyst/examples/arbitrage_with_interface.py
imports: from logbook import Logger
  from catalyst.api import record, order, symbol
  from catalyst.exchange.utils.stats_utils import get_pretty_stats
  from catalyst.utils.run_algo import run_algorithm
label_desc: Use image node_id 3 for calling a global function with example usage: handle_data(context, data) without return types