Java 8 streams - restructure entity classes for UI Grid
Type inference for generic instance creation
You can rely on type inference for generic instance creation when declaring unifiedHoldings:
List&lt;Map&lt;DataSource, List&lt;Holding&gt;&gt;&gt; unifiedHoldings = new ArrayList&lt;&gt;();

Mutable operations on collections
List&lt;Holding&gt; aSourceHoldings = holdingService.getHoldings(date);
List&lt;Holding&gt; unMatchedHoldings = /* ... */ ;
aSourceHoldings.removeAll(unMatchedHoldings);
List&lt;Holding&gt; toBeMatchedHoldings = holdingRepository.getHoldings(date);
toBeMatchedHoldings.addAll(aSourceHoldings);

Calling mutable operations such as removeAll(Collection) and addAll(Collection) may throw UnsupportedOperationException if the underlying List does not return a mutable implementation. As such, in these scenarios, you should be creating your own List given the resulting elements, and then do the necessary removal/addition calls on the new instance.
Account and Product usage
Interestingly, it looks like Account and Product themselves aren't used in the processing, after kind of using them as 'keys' for grouping. The nested Maps looks too peculiar, which brings us to the next point...
Grouping your Holding objects

I currently break up the list of holdings into several lists where each list contains only holdings with the same product id and account. Also, I key each list by data source.
(emphasis mine)

This looks like a good use case for a supplementary 'key' class that will allow us to grouping Holding objects with the same account, product and data source. For example:
private static final class HoldingKey {
    private final Account account;
    private final Product product;

    HoldingKey(Account account, Product product) {
        this.account = Objects.requireNonNull(account);
        this.product = Objects.requireNonNull(product);
    }

    Account getAccount() {
        return account;
    }

    Product getProduct() {
        return product;
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof HoldingKey
                &amp;&amp; getAccount().equals(((HoldingKey) o).getAccount())
                &amp;&amp; getProduct().equals(((HoldingKey) o).getProduct());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getAccount(), getProduct());
    }

    static HoldingKey toKey(Holding holding) {
        return new HoldingKey(holding.getAccount(), 
                                holding.getDataSourceProduct().getProduct());
    }
}

Using the method reference HoldingKey::toKey to group Holding objects by, with a dash of Stream.concat(Stream, Stream) to combine two streams together, we can combine the processing on both the repository and service results with relative ease:
    Stream&lt;Holding&gt; fromRepository = holdingRepository.getHoldings(date).stream();
    Stream&lt;Holding&gt; fromService = holdingService.getHoldings(date).stream()
            .filter(h -&gt; h.getDataSourceProduct().getProduct().getId() != null);
    Map&lt;HoldingKey, List&lt;Holding&gt;&gt; map = Stream.concat(fromRepository, fromService)
            .collect(Collectors.groupingBy(HoldingKey::toKey));

This simplifies the nested Maps we have by flattening that multi-key structure into a single HoldingKey object. Achieving what you require is a simple continuation on map's entrySet(), with a mapping function to turn List&lt;Holding&gt; into your required Map&lt;DataSource, Holding&gt;:
private static final Function&lt;List&lt;Holding&gt;, Map&lt;DataSource, Holding&gt;&gt; MAPPER =
        x -&gt; x.stream().collect(Collectors.toMap(
                y -&gt; y.getDataSourceProduct().getDataSource(), Function.identity()));

private static List&lt;Map&lt;DataSource, List&lt;Holding&gt;&gt;&gt; getUnifiedHoldings(Date date) {
    Stream&lt;Holding&gt; fromRepository = holdingRepository.getHoldings(date).stream();
    Stream&lt;Holding&gt; fromService = holdingService.getHoldings(date).stream()
            .filter(h -&gt; h.getDataSourceProduct().getProduct().getId() != null);
    return Stream.concat(fromRepository, fromService)
            .collect(Collectors.groupingBy(HoldingKey::toKey))
            .entrySet()
            .stream()
            .map(MAPPER.compose(Map.Entry::getValue))
            .collect(Collectors.toList());
}

Here, we compose() our MAPPER function with the 'extractor' function Map.Entry::getValue to derive our resulting list elements.