def test_match_recommendations_one_offer_multiple_bids(self, market): """Test match_recommendations() method of TwoSidedMarket using 1 offer N bids.""" bid1 = Bid("bid_id1", pendulum.now(), price=1, energy=1, buyer="Buyer") bid2 = Bid("bid_id2", pendulum.now(), price=1, energy=1, buyer="Buyer") offer1 = Offer("offer_id1", pendulum.now(), price=2, energy=2, seller="Seller") market.bids = {"bid_id1": bid1, "bid_id2": bid2} market.offers = {"offer_id1": offer1} recommendations = [ BidOfferMatch( bids=[bid.serializable_dict() for bid in market.bids.values()], offers=[ offer.serializable_dict() for offer in market.offers.values() ], trade_rate=1, selected_energy=1, market_id=market.id).serializable_dict() ] market.match_recommendations(recommendations) assert len(market.trades) == 2
def test_match_recommendations_fake_offer_bid(self, market, two_sided_market_matching): """Test the case when an offer or bid which don't belong to market is sent.""" bid = Bid("bid_id1", pendulum.now(), price=2, energy=1, buyer="B") offer = Offer("id", pendulum.now(), price=2, energy=1, seller="other") market.bids = {"bid_id1": bid} recommendations = [ BidOfferMatch(bids=[bid.serializable_dict()], offers=[offer.serializable_dict()], trade_rate=2, selected_energy=1, market_id=market.id).serializable_dict() ] # The sent offer isn't in market offers, should be skipped market.match_recommendations(recommendations) assert len(market.trades) == 0 assert not market.validate_bid_offer_match.called assert not market.accept_bid_offer_pair.called assert not market._replace_offers_bids_with_residual_in_recommendations_list.called market.offers = {offer.id: offer} market.bids = {} # The sent bid isn't in market offers, should be skipped market.match_recommendations(recommendations) assert len(market.trades) == 0 assert not market.validate_bid_offer_match.called assert not market.accept_bid_offer_pair.called assert not market._replace_offers_bids_with_residual_in_recommendations_list.called
def test_double_sided_validate_requirements_satisfied(self, market): offer = Offer("id", pendulum.now(), 2, 2, "other", 2, requirements=[{ "trading_partners": ["bid_id2"] }], attributes={"energy_type": "Green"}) bid = Bid("bid_id", pendulum.now(), 9, 10, "B", 9, buyer_id="bid_id", requirements=[], attributes={}) with pytest.raises(InvalidBidOfferPairException): # should raise an exception as buyer_id is not in trading_partners market._validate_requirements_satisfied(bid, offer) bid.buyer_id = "bid_id2" market._validate_requirements_satisfied( bid, offer) # Should not raise any exceptions bid.requirements.append({"energy_type": ["Grey"]}) with pytest.raises(InvalidBidOfferPairException): # should raise an exception as energy_type of offer needs to be in [Grey, ] market._validate_requirements_satisfied(bid, offer) # Adding another requirement that is satisfied, should not raise an exception bid.requirements.append({"energy_type": ["Green"]}) market._validate_requirements_satisfied(bid, offer)
def test_get_bids(self, market): """Test the get_bids() method of TwoSidedMarket.""" market.bids = { "bid1": Bid("bid1", pendulum.now(), 9, 10, "B", 9, buyer_id="bid_id"), "bid2": Bid("bid2", pendulum.now(), 9, 10, "B", 9, buyer_id="bid_id"), "bid3": Bid("bid3", pendulum.now(), 9, 10, "B", 9, buyer_id="bid_id") } assert market.get_bids() == market.bids
def _populate_market_bids_offers(self): self.market.offers = { "id1": Offer("id1", now(), 3, 3, "seller", 3), "id2": Offer("id2", now(), 0.5, 1, "seller", 0.5) } self.market.bids = { "id3": Bid("id3", now(), 1, 1, "buyer", 1), "id4": Bid("id4", now(), 0.5, 1, "buyer", 1) }
def test_delete_bid(self, market): """Test the delete_bid method of TwoSidedMarket.""" bid1 = Bid("bid1", pendulum.now(), 9, 10, "B", 9, buyer_id="bid_id") bid2 = Bid("bid2", pendulum.now(), 9, 10, "B", 9, buyer_id="bid_id") market.bids = { "bid1": bid1, "bid2": bid2, } market.delete_bid("bid1") assert "bid1" not in market.bids assert len(market.bids) == 1 market.delete_bid(bid2) assert len(market.bids) == 0 with pytest.raises(BidNotFoundException): market.delete_bid(bid2)
def test_matching_list_gets_updated_with_residual_offers(self): matches = [ BidOfferMatch(offers=[ Offer("offer_id", pendulum.now(), 1, 1, "S").serializable_dict() ], selected_energy=1, bids=[ Bid("bid_id", pendulum.now(), 1, 1, "B").serializable_dict() ], trade_rate=1, market_id="").serializable_dict(), BidOfferMatch(offers=[ Offer("offer_id2", pendulum.now(), 2, 2, "S").serializable_dict() ], selected_energy=2, bids=[ Bid("bid_id2", pendulum.now(), 2, 2, "B").serializable_dict() ], trade_rate=1, market_id="").serializable_dict() ] offer_trade = Trade("trade", 1, Offer("offer_id", pendulum.now(), 1, 1, "S"), "S", "B", residual=Offer("residual_offer", pendulum.now(), 0.5, 0.5, "S")) bid_trade = Trade("bid_trade", 1, Bid("bid_id2", pendulum.now(), 1, 1, "S"), "S", "B", residual=Bid("residual_bid_2", pendulum.now(), 1, 1, "S")) matches = TwoSidedMarket._replace_offers_bids_with_residual_in_recommendations_list( matches, offer_trade, bid_trade) assert len(matches) == 2 assert matches[0]["offers"][0]["id"] == "residual_offer" assert matches[1]["bids"][0]["id"] == "residual_bid_2"
def test_match_recommendations(self, market): """Test match_recommendations() method of TwoSidedMarket.""" bid = Bid("bid_id1", pendulum.now(), price=2, energy=1, buyer="Buyer") offer = Offer("offer_id1", pendulum.now(), price=2, energy=1, seller="Seller") market.bids = {"bid_id1": bid} market.offers = {"offer_id1": offer} recommendations = [ BidOfferMatch(bids=[bid.serializable_dict()], offers=[offer.serializable_dict()], trade_rate=2, selected_energy=1, market_id=market.id).serializable_dict() ] market.match_recommendations(recommendations) assert len(market.trades) == 1
def test_double_sided_pay_as_clear_market_works_with_floats( self, pac_market): ConstSettings.IAASettings.PAY_AS_CLEAR_AGGREGATION_ALGORITHM = 1 offers = [ Offer("id1", pendulum.now(), 1.1, 1, "other").serializable_dict(), Offer("id2", pendulum.now(), 2.2, 1, "other").serializable_dict(), Offer("id3", pendulum.now(), 3.3, 1, "other").serializable_dict() ] bids = [ Bid("bid_id1", pendulum.now(), 3.3, 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id2", pendulum.now(), 2.2, 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id3", pendulum.now(), 1.1, 1, "B", buyer_origin="S").serializable_dict() ] matched = pac_market.get_clearing_point(bids, offers, pendulum.now())[0] assert matched == 2.2
def test_validate_bid_offer_match_raises_exception(self, market, bid_energy, offer_energy, clearing_rate, selected_energy): offer = Offer("id", pendulum.now(), 2, offer_energy, "other", 2) bid = Bid("bid_id", pendulum.now(), 2, bid_energy, "B", 8) market._validate_requirements_satisfied = MagicMock() with pytest.raises(InvalidBidOfferPairException): market.validate_bid_offer_match([bid], [offer], clearing_rate, selected_energy) market._validate_requirements_satisfied.assert_not_called()
def test_double_sided_market_performs_pay_as_clear_matching( self, pac_market, offer, bid, mcp_rate, mcp_energy, algorithm): ConstSettings.IAASettings.PAY_AS_CLEAR_AGGREGATION_ALGORITHM = algorithm offers = [ Offer("id1", pendulum.now(), offer[0], 1, "other").serializable_dict(), Offer("id2", pendulum.now(), offer[1], 1, "other").serializable_dict(), Offer("id3", pendulum.now(), offer[2], 1, "other").serializable_dict(), Offer("id4", pendulum.now(), offer[3], 1, "other").serializable_dict(), Offer("id5", pendulum.now(), offer[4], 1, "other").serializable_dict(), Offer("id6", pendulum.now(), offer[5], 1, "other").serializable_dict(), Offer("id7", pendulum.now(), offer[6], 1, "other").serializable_dict() ] bids = [ Bid("bid_id1", pendulum.now(), bid[0], 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id2", pendulum.now(), bid[1], 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id3", pendulum.now(), bid[2], 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id4", pendulum.now(), bid[3], 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id5", pendulum.now(), bid[4], 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id6", pendulum.now(), bid[5], 1, "B", buyer_origin="S").serializable_dict(), Bid("bid_id7", pendulum.now(), bid[6], 1, "B", buyer_origin="S").serializable_dict() ] matched_rate, matched_energy = pac_market.get_clearing_point( bids, offers, pendulum.now()) assert matched_rate == mcp_rate assert matched_energy == mcp_energy
def bid(): return Bid("bid_id", now(), 9, 10, "B", 9)
def test_double_sided_performs_pay_as_bid_matching(self, market: TwoSidedMarket, market_matcher): market.offers = { "offer1": Offer("id", pendulum.now(), 2, 2, "other", 2) } market.bids = { "bid1": Bid("bid_id", pendulum.now(), 9, 10, "B", buyer_origin="S") } matched = market_matcher.get_matches_recommendations({ market.id: { "bids": [bid.serializable_dict() for bid in market.bids.values()], "offers": [ offer.serializable_dict() for offer in market.offers.values() ] } }) assert len(matched) == 0 market.bids = { "bid1": Bid("bid_id", pendulum.now(), 11, 10, "B", buyer_origin="S") } matched = market_matcher.get_matches_recommendations({ market.id: { "bids": [bid.serializable_dict() for bid in market.bids.values()], "offers": [ offer.serializable_dict() for offer in market.offers.values() ] } }) assert len(matched) == 1 assert len(matched[0]["bids"]) == 1 assert len(matched[0]["offers"]) == 1 assert matched[0]["bids"][0] == list( market.bids.values())[0].serializable_dict() assert matched[0]["offers"][0] == list( market.offers.values())[0].serializable_dict() market.bids = { "bid1": Bid("bid_id1", pendulum.now(), 11, 10, "B", buyer_origin="S"), "bid2": Bid("bid_id2", pendulum.now(), 9, 10, "B", buyer_origin="S"), "bid3": Bid("bid_id3", pendulum.now(), 12, 10, "B", buyer_origin="S") } matched = market_matcher.get_matches_recommendations({ market.id: { "bids": [bid.serializable_dict() for bid in market.bids.values()], "offers": [ offer.serializable_dict() for offer in market.offers.values() ] } }) assert len(matched) == 1 assert matched[0]["bids"][0]["id"] == "bid_id3" assert matched[0]["bids"][0]["energy_rate"] == 1.2 assert matched[0]["bids"][0]["energy"] == 10 assert matched[0]["offers"][0] == list( market.offers.values())[0].serializable_dict()