Search code examples
javasortingcollections

Java sorting by spread between two BigDecimal


Please help with sorting in Java. I have a simple example (looks like this). I need to sort list by the difference between two BigDecimals.

My Data class (I cut getters)

    public class Quotation {
    private final long id;
    private final BigDecimal askPrice;
    private final BigDecimal bidPrice;

    public Quotation(long id, BigDecimal bidPrice, BigDecimal askPrice) {
        this.id = id;
        this.askPrice = askPrice;
        this.bidPrice = bidPrice;
    }
    }

Here we store our records.

        storeQuotation(new Quotation(1000,new BigDecimal("99"), new BigDecimal("104")));
        storeQuotation(new Quotation(1001,new BigDecimal("69"), new BigDecimal("72")));
        storeQuotation(new Quotation(1002,new BigDecimal("65"), new BigDecimal("69")));
        storeQuotation(new Quotation(1003,new BigDecimal("70"), new BigDecimal("71")));
        storeQuotation(new Quotation(1004,new BigDecimal("71"), new BigDecimal("73")));
        storeQuotation(new Quotation(1005,new BigDecimal("90"), new BigDecimal("95")));
        storeQuotation(new Quotation(1006,new BigDecimal("92"), new BigDecimal("93")));
        storeQuotation(new Quotation(1007,new BigDecimal("94"), new BigDecimal("98")));
        storeQuotation(new Quotation(1008,new BigDecimal("90"), new BigDecimal("92")));
        storeQuotation(new Quotation(1009,new BigDecimal("92"), new BigDecimal("95")));
out - Not Sorted
    id - 1000.   Bid - 99.   Ask - 104.   Spread = 5
    id - 1001.   Bid - 69.   Ask - 72.   Spread = 3
    id - 1002.   Bid - 65.   Ask - 69.   Spread = 4
    id - 1003.   Bid - 70.   Ask - 71.   Spread = 1
    id - 1004.   Bid - 71.   Ask - 73.   Spread = 2
    id - 1005.   Bid - 90.   Ask - 95.   Spread = 5
    id - 1006.   Bid - 92.   Ask - 93.   Spread = 1
    id - 1007.   Bid - 94.   Ask - 98.   Spread = 4
    id - 1008.   Bid - 90.   Ask - 92.   Spread = 2
    id - 1009.   Bid - 92.   Ask - 95.   Spread = 3

And I just need to sort this list by the difference between bidPrice and askPrice. I tried this method...

    public static List<Quotation> getSpreadsList(boolean decreasing) {
        List<Quotation> sortedBySpread = QuotationsStoreImpl.quotationList;

        Collections.sort(sortedBySpread, (a, b) ->
     (a.getBidPrice().intValue() - b.getAskPrice().intValue()));

//        sortedBySpread.sort((a, b) -> 
//    (a.getBidPrice().intValue() - b.getAskPrice().intValue()));

        if (decreasing) {
            Collections.reverse(sortedBySpread);
        }
        return sortedBySpread;
    }
    }

But without success...

out - Sorted
    id - 1002.   Bid - 65.   Ask - 69.   Spread = 4
    id - 1003.   Bid - 70.   Ask - 71.   Spread = 1
    id - 1004.   Bid - 71.   Ask - 73.   Spread = 2
    id - 1001.   Bid - 69.   Ask - 72.   Spread = 3
    id - 1008.   Bid - 90.   Ask - 92.   Spread = 2
    id - 1009.   Bid - 92.   Ask - 95.   Spread = 3
    id - 1006.   Bid - 92.   Ask - 93.   Spread = 1
    id - 1007.   Bid - 94.   Ask - 98.   Spread = 4
    id - 1005.   Bid - 90.   Ask - 95.   Spread = 5
    id - 1000.   Bid - 99.   Ask - 104.   Spread = 5

The list is mixed but not sorted according to my criteria ! Spread not sorted !

How can I sort this list correct, by spread ?

I don't have much experience in java. And all my attempts have come to nothing.


Solution

  • Collections.sort(sortedBySpread, (a, b) -> (a.getBidPrice().intValue() - b.getAskPrice().intValue())); does some math that makes little since since it subtracts the ask from the bid of two different quotes.

    Instead you should calculate the spread of a and then subtract the spread of b:

    Collections.sort(sortedBySpread, (a, b) -> (a.getBidPrice().intValue() - a.getAskPrice().intValue()) - (b.getBidPrice().intValue() - b.getAskPrice().intValue()));
    

    Generally this could be expanded into the following to make it more clear what is going on:

    Collections.sort(sortedBySpread, (Quotation a, Quotation b) -> {
        int spreadA = a.getBidPrice().intValue() - a.getAskPrice().intValue();
        int spreadB = b.getBidPrice().intValue() - b.getAskPrice().intValue();
        return spreadA - spreadB;
    });
    

    But starting with the first snippet IntelliJ suggest the arguably far cleaner solution

    Collections.sort(sortedBySpread, Comparator.comparingInt(a -> (a.getBidPrice().intValue() - a.getAskPrice().intValue())));
    

    And going from there it might make sense to have a getSpread on Quotation:

    public int getSpread() {
        return bidPrice.intValue() - askPrice.intValue();
    }
    

    which would then allow

    Collections.sort(sortedBySpread, Comparator.comparingInt(Quotation::getSpread));
    

    And finally

    sortedBySpread.sort(Comparator.comparingInt(Quotation::getSpread));
    

    without the need for Collections.sort.