class TradeTokenEvaluator extends TokenEvaluator<Trade> {

  @Override
  public EvaluationResult evaluate(
      Trade trade,
      CalculationFunctions functions,
      String firstToken,
      List<String> remainingTokens) {

    MetaBean metaBean = MetaBean.of(trade.getClass());

    // trade
    Optional<String> tradePropertyName = metaBean.metaPropertyMap().keySet().stream()
        .filter(p -> p.equalsIgnoreCase(firstToken))
        .findFirst();

    if (tradePropertyName.isPresent()) {
      Object propertyValue = metaBean.metaProperty(tradePropertyName.get()).get((Bean) trade);
      if (propertyValue == null) {
        return EvaluationResult.failure("Property '{}' not set", firstToken);
      }
      return EvaluationResult.success(propertyValue, remainingTokens);
    }

    // trade info
    Optional<String> tradeInfoPropertyName = trade.getInfo().propertyNames().stream()
        .filter(p -> p.equalsIgnoreCase(firstToken))
        .findFirst();

    if (tradeInfoPropertyName.isPresent()) {
      Object propertyValue = trade.getInfo().property(tradeInfoPropertyName.get()).get();
      if (propertyValue == null) {
        return EvaluationResult.failure("Property '{}' not set", firstToken);
      }
      return EvaluationResult.success(propertyValue, remainingTokens);
    }
    return invalidTokenFailure(trade, firstToken);
  }

}