getConfiguration = async (logger, symbol = null) => {
  // To reduce MongoDB query, try to get cached configuration first.
  const cachedConfiguration =
    JSON.parse(
      await cache.hgetWithoutLock(
        'trailing-trade-configurations',
        `${symbol || 'global'}`
      )
    ) || {};

  if (_.isEmpty(cachedConfiguration) === false) {
    return cachedConfiguration;
  }

  // If symbol is not provided, then it only looks up global configuration
  const globalConfigValue = await getGlobalConfiguration(logger);
  const symbolConfigValue = await getSymbolConfiguration(logger, symbol);
  const symbolGridTrade = await getSymbolGridTrade(logger, symbol);

  // Merge global and symbol configuration without grid trade if symbol is provided.
  let mergedConfigValue = _.defaultsDeep(
    symbolConfigValue,
    symbol !== null
      ? _.omit(
          globalConfigValue,
          'buy.gridTrade',
          'sell.gridTrade',
          'botOptions.tradingViews'
        )
      : globalConfigValue
  );
  let cachedSymbolInfo;

  if (symbol !== null) {
    cachedSymbolInfo =
      JSON.parse(
        await cache.hgetWithoutLock(
          'trailing-trade-symbols',
          `${symbol}-symbol-info`
        )
      ) || {};

    // Post process configuration value to prefill some default values
    [
      {
        key: 'buy.gridTrade',
        keyFunc: getGridTradeBuy
      },
      {
        key: 'buy.lastBuyPriceRemoveThreshold',
        keyFunc: getLastBuyPriceRemoveThreshold
      },
      {
        key: 'sell.gridTrade',
        keyFunc: getGridTradeSell
      },
      {
        key: 'botOptions.tradingViews',
        keyFunc: getBotOptionTradingViews
      }
    ].forEach(d => {
      const { key, keyFunc } = d;
      _.set(
        mergedConfigValue,
        key,
        keyFunc(logger, cachedSymbolInfo, globalConfigValue, symbolConfigValue)
      );
    });

    // For symbol configuration, remove lastBuyPriceRemoveThresholds
    _.unset(mergedConfigValue, 'buy.lastBuyPriceRemoveThresholds');

    // Post process configuration to get current grid trade
    mergedConfigValue = await postProcessConfiguration(
      logger,
      mergedConfigValue,
      { symbolGridTrade, symbol }
    );
  }

  // Save final configuration to cache
  if (symbol === null || _.isEmpty(cachedSymbolInfo) === false) {
    await cache.hset(
      'trailing-trade-configurations',
      `${symbol || 'global'}`,
      JSON.stringify(mergedConfigValue)
    );
  }

  return mergedConfigValue;
}
Get global/symbol configuration

@param {*} logger
@param {*} symbol