Пример #1
0
 def bid(self,
         price,
         energy,
         buyer,
         seller,
         original_bid_price=None,
         buyer_origin=None):
     return Bid(123,
                price,
                energy,
                buyer,
                seller,
                original_bid_price,
                buyer_origin=buyer_origin)
Пример #2
0
 def test_bid_calls_market_method_and_publishes_response(self):
     payload = {
         "data":
         json.dumps({
             "buyer": "mykonos",
             "energy": 12,
             "price": 32,
             "transaction_uuid": "trans_id"
         })
     }
     bid = Bid("b_id", 32, 12, "b_buyer", "b_seller")
     self.market.bid = MagicMock(return_value=bid)
     self.subscriber._bid(payload)
     self.subscriber.market.bid.assert_called_once_with(buyer="mykonos",
                                                        energy=12,
                                                        price=32)
     self.subscriber.redis_db.publish.assert_called_once_with(
         "id/BID/RESPONSE",
         json.dumps({
             "status": "ready",
             "bid": bid.to_JSON_string(),
             "transaction_uuid": "trans_id"
         }))
Пример #3
0
    def test_matching_list_affects_only_matches_after_start_index(self):
        matchings = [
            BidOfferMatch(offer=Offer('offer_id', pendulum.now(), 1, 1, 'S'),
                          offer_energy=1,
                          bid=Bid('bid_id', pendulum.now(), 1, 1, 'B', 'S'),
                          bid_energy=1),
            BidOfferMatch(offer=Offer('offer_id2', pendulum.now(), 2, 2, 'S'),
                          offer_energy=2,
                          bid=Bid('bid_id2', pendulum.now(), 2, 2, 'B', 'S'),
                          bid_energy=2),
            BidOfferMatch(offer=Offer('offer_id', pendulum.now(), 1, 1, 'S'),
                          offer_energy=1,
                          bid=Bid('bid_id', pendulum.now(), 1, 1, 'B', 'S'),
                          bid_energy=1)
        ]

        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', 'B'),
                          'S',
                          'B',
                          residual=Bid('residual_bid_2', pendulum.now(), 1, 1,
                                       'S', 'B'))

        matchings = TwoSidedPayAsClear._replace_offers_bids_with_residual_in_matching_list(
            matchings, 1, offer_trade, bid_trade)
        assert len(matchings) == 3
        assert matchings[0].offer.id == 'offer_id'
        assert matchings[1].bid.id == 'residual_bid_2'
        assert matchings[2].offer.id == 'residual_offer'
Пример #4
0
def test_iaa_event_trade_bid_updates_forwarded_bids_on_partial(
        iaa_bid, called, partial):
    iaa_bid.lower_market.delete_bid = called
    low_to_high_engine = iaa_bid.engines[0]
    iaa_bid._get_market_from_market_id = lambda x: low_to_high_engine.markets.target
    if partial:
        accepted_bid = Bid(*low_to_high_engine.markets.target._bids[0])
        accepted_bid = \
            accepted_bid._replace(price=(accepted_bid.energy-0.2) *
                                        (accepted_bid.price/accepted_bid.energy),
                                  energy=accepted_bid.energy-0.2)
        partial_bid = Bid('1234', 12, 0.2, 'owner', 'someone_else')
        low_to_high_engine.event_bid_changed(
            market_id=low_to_high_engine.markets.target,
            existing_bid=accepted_bid,
            new_bid=partial_bid)
    else:
        accepted_bid = low_to_high_engine.markets.target._bids[0]
        partial_bid = False
    source_bid = list(low_to_high_engine.markets.source.bids.values())[0]
    target_bid = list(low_to_high_engine.markets.target.bids.values())[0]
    bidinfo = BidInfo(source_bid=source_bid, target_bid=target_bid)
    low_to_high_engine.forwarded_bids[source_bid.id] = bidinfo
    low_to_high_engine.forwarded_bids[target_bid.id] = bidinfo

    low_to_high_engine.event_bid_traded(bid_trade=Trade('trade_id',
                                                        pendulum.now(
                                                            tz=TIME_ZONE),
                                                        accepted_bid,
                                                        seller='someone_else',
                                                        buyer='owner',
                                                        residual=partial_bid))

    assert source_bid.id not in low_to_high_engine.forwarded_bids
    assert target_bid.id not in low_to_high_engine.forwarded_bids
    if partial:
        assert partial_bid.id in low_to_high_engine.forwarded_bids
 def bid(self,
         price,
         energy,
         buyer,
         seller,
         original_bid_price=None,
         buyer_origin=None):
     bid = Bid("bid_id",
               pendulum.now(),
               price,
               energy,
               buyer,
               seller,
               buyer_origin=buyer_origin)
     return bid
Пример #6
0
 def bid(self,
         price: float,
         energy: float,
         buyer: str,
         seller: str,
         bid_id: str = None) -> Bid:
     if energy <= 0:
         raise InvalidBid()
     bid = Bid(
         str(uuid.uuid4()) if bid_id is None else bid_id, price, energy,
         buyer, seller, self)
     self.bids[bid.id] = bid
     self.bid_history.append(bid)
     log.info(f"[BID][NEW][{self.time_slot_str}] {bid}")
     return bid
Пример #7
0
def test_iaa_double_sided_performs_pay_as_bid_matching(iaa_double_sided_2):
    low_high_engine = next(filter(lambda e: e.name == "Low -> High", iaa_double_sided_2.engines))

    iaa_double_sided_2.lower_market._bids = [Bid('bid_id', 9, 10, 'B', 'S')]
    matched = list(low_high_engine._perform_pay_as_bid_matching())
    assert len(matched) == 0

    iaa_double_sided_2.lower_market._bids = [Bid('bid_id', 10, 10, 'B', 'S')]
    matched = list(low_high_engine._perform_pay_as_bid_matching())
    assert len(matched) == 1
    bid, offer = matched[0]
    assert bid == list(iaa_double_sided_2.lower_market.bids.values())[0]
    assert offer == list(iaa_double_sided_2.lower_market.offers.values())[0]

    iaa_double_sided_2.lower_market._bids = [Bid('bid_id1', 11, 10, 'B', 'S'),
                                             Bid('bid_id2', 9, 10, 'B', 'S'),
                                             Bid('bid_id3', 12, 10, 'B', 'S')]
    matched = list(low_high_engine._perform_pay_as_bid_matching())
    assert len(matched) == 1
    bid, offer = matched[0]
    assert bid.id == 'bid_id3'
    assert bid.price == 12
    assert bid.energy == 10
    assert offer == list(iaa_double_sided_2.lower_market.offers.values())[0]
Пример #8
0
def test_double_sided_pay_as_bid_market_match_offer_bids(pab_market):
    pab_market.calls_offers = []
    pab_market.calls_bids = []
    offer = Offer('offer1', now(), 2, 2, 'other', 2)
    pab_market.offers = {"offer1": offer}

    source_bid = Bid('bid_id3', now(), 12, 10, 'B', 'S', original_bid_price=12)
    pab_market.bids = {"bid_id": Bid('bid_id', now(), 10, 10, 'B', 'S'),
                       "bid_id1": Bid('bid_id1', now(), 11, 10, 'B', 'S'),
                       "bid_id2": Bid('bid_id2', now(), 9, 10, 'B', 'S'),
                       "bid_id3": source_bid}

    pab_market.match_offers_bids()
    assert len(pab_market.calls_offers) == 1
    offer = pab_market.calls_offers[0]
    assert offer.id == offer.id
    assert offer.energy == offer.energy
    assert offer.price == offer.price

    assert len(pab_market.calls_bids) == 1
    bid = pab_market.calls_bids[0]
    assert bid.id == source_bid.id
    assert bid.energy == source_bid.energy
    assert bid.price == source_bid.price
Пример #9
0
    def accept_bid(self, bid, energy, seller, buyer=None, *, time=None, trade_rate: float = None,
                   trade_offer_info=None, already_tracked=False, seller_origin=None):
        self.calls_energy_bids.append(energy)
        self.calls_bids.append(bid)
        self.calls_bids_price.append(bid.price)
        if trade_rate is None:
            trade_rate = bid.price / bid.energy
        else:
            assert trade_rate <= (bid.price / bid.energy)

        market_bid = [b for b in self._bids if b.id == bid.id][0]
        if energy < market_bid.energy:
            residual_energy = bid.energy - energy
            residual = Bid('res', bid.price, residual_energy, bid.buyer, seller,
                           buyer_origin='res')
            traded = Bid(bid.id, (trade_rate * energy), energy, bid.buyer, seller,
                         buyer_origin='res')
            return Trade('trade_id', time, traded, traded.seller, bid.buyer, residual,
                         buyer_origin=bid.buyer_origin, seller_origin=seller_origin)
        else:
            traded = Bid(bid.id, (trade_rate * energy), energy, bid.buyer, seller,
                         buyer_origin=bid.id)
            return Trade('trade_id', time, traded, traded.seller, bid.buyer,
                         buyer_origin=bid.buyer_origin, seller_origin=seller_origin)
Пример #10
0
def test_double_sided_performs_pay_as_bid_matching(market):
    market.offers = {"offer1": Offer('id', now(), 2, 2, 'other', 2)}

    market.bids = {"bid1": Bid('bid_id', now(), 9, 10, 'B', 'S')}
    matched = list(market._perform_pay_as_bid_matching())
    assert len(matched) == 0
    market.bids = {"bid1": Bid('bid_id', now(), 10, 10, 'B', 'S')}
    matched = list(market._perform_pay_as_bid_matching())
    assert len(matched) == 1

    bid, offer = matched[0]
    assert bid == list(market.bids.values())[0]
    assert offer == list(market.offers.values())[0]

    market.bids = {"bid1": Bid('bid_id1', now(), 11, 10, 'B', 'S'),
                   "bid2": Bid('bid_id2', now(), 9, 10, 'B', 'S'),
                   "bid3": Bid('bid_id3', now(), 12, 10, 'B', 'S')}
    matched = list(market._perform_pay_as_bid_matching())
    assert len(matched) == 1
    bid, offer = matched[0]
    assert bid.id == 'bid_id3'
    assert bid.price == 12
    assert bid.energy == 10
    assert offer == list(market.offers.values())[0]
 def bid(self,
         price: float,
         energy: float,
         buyer: str,
         seller: str,
         original_bid_price=None,
         buyer_origin=None) -> Bid:
     bid = Bid(id='bid_id',
               price=price,
               energy=energy,
               buyer=buyer,
               seller=seller,
               original_bid_price=original_bid_price,
               buyer_origin=buyer_origin)
     self.bids[bid.id] = bid
     return bid
Пример #12
0
 def bid(self,
         price,
         energy,
         buyer,
         seller,
         original_bid_price=None,
         buyer_origin=None):
     self.bid_count += 1
     self.forwarded_bid = Bid(self.forwarded_bid_id,
                              price,
                              energy,
                              buyer,
                              seller,
                              original_bid_price=original_bid_price,
                              buyer_origin=buyer_origin)
     return self.forwarded_bid
Пример #13
0
def iaa_double_sided():
    from d3a_interface.constants_limits import ConstSettings
    ConstSettings.IAASettings.MARKET_TYPE = 2
    lower_market = FakeMarket(offers=[Offer('id', pendulum.now(), 2, 2, 'other', 2)],
                              bids=[Bid('bid_id', pendulum.now(), 10, 10, 'B', 'S', 10)],
                              transfer_fees=TransferFees(grid_fee_percentage=0.01,
                                                         transfer_fee_const=0))
    higher_market = FakeMarket([], [], transfer_fees=TransferFees(grid_fee_percentage=0.01,
                                                                  transfer_fee_const=0))
    owner = FakeArea('owner')
    iaa = TwoSidedPayAsBidAgent(owner=owner, lower_market=lower_market,
                                higher_market=higher_market)
    iaa.event_tick()
    iaa.owner.current_tick += 2
    iaa.event_tick()
    yield iaa
Пример #14
0
    def bid(self,
            price: float,
            energy: float,
            buyer: str,
            buyer_origin: str,
            bid_id: str = None,
            original_bid_price=None,
            adapt_price_with_fees=True,
            add_to_history=True,
            buyer_origin_id=None,
            buyer_id=None,
            attributes: Dict = None,
            requirements: List[Dict] = None) -> Bid:
        if energy <= 0:
            raise InvalidBid()

        if original_bid_price is None:
            original_bid_price = price

        if adapt_price_with_fees:
            price = self._update_new_bid_price_with_fee(
                price, original_bid_price)

        if price < 0.0:
            raise MarketException(
                "Negative price after taxes, bid cannot be posted.")

        bid = Bid(str(uuid.uuid4()) if bid_id is None else bid_id,
                  self.now,
                  price,
                  energy,
                  buyer,
                  original_bid_price,
                  buyer_origin,
                  buyer_origin_id=buyer_origin_id,
                  buyer_id=buyer_id,
                  attributes=attributes,
                  requirements=requirements)

        self.bids[bid.id] = bid
        if add_to_history is True:
            self.bid_history.append(bid)
        log.debug(f"[BID][NEW][{self.time_slot_str}] {bid}")
        return bid
Пример #15
0
    def bid(self, price: float, energy: float, buyer: str, seller: str, buyer_origin,
            bid_id: str = None, original_bid_price=None, adapt_price_with_fees=True,
            add_to_history=True) -> Bid:
        if energy <= 0:
            raise InvalidBid()

        if original_bid_price is None:
            original_bid_price = price

        if adapt_price_with_fees:
            price = self._update_new_bid_price_with_fee(price, original_bid_price)

        bid = Bid(str(uuid.uuid4()) if bid_id is None else bid_id,
                  self.now, price, energy, buyer, seller, original_bid_price, buyer_origin)
        self.bids[bid.id] = bid
        if add_to_history is True:
            self.bid_history.append(bid)
        log.debug(f"[BID][NEW][{self.time_slot_str}] {bid}")
        return bid
Пример #16
0
    def test_create_bid_offer_matchings_can_match_with_only_one_bid(self):
        bid_list = [Bid('bid_id', pendulum.now(), 9, 90123456789, 'B', 'S')]

        offer_list = [
            Offer('offer_id', pendulum.now(), 1, 1, 'S'),
            Offer('offer_id1', pendulum.now(), 2, 2, 'S'),
            Offer('offer_id2', pendulum.now(), 3, 3, 'S'),
            Offer('offer_id3', pendulum.now(), 4, 4, 'S'),
            Offer('offer_id4', pendulum.now(), 5, 5, 'S')
        ]

        matchings = TwoSidedPayAsClear._create_bid_offer_matchings(
            15, offer_list, bid_list)

        assert len(matchings) == 5
        self.validate_matching(matchings[0], 1, 'offer_id', 'bid_id')
        self.validate_matching(matchings[1], 2, 'offer_id1', 'bid_id')
        self.validate_matching(matchings[2], 3, 'offer_id2', 'bid_id')
        self.validate_matching(matchings[3], 4, 'offer_id3', 'bid_id')
        self.validate_matching(matchings[4], 5, 'offer_id4', 'bid_id')
Пример #17
0
 def bid(self,
         price,
         energy,
         buyer,
         original_bid_price=None,
         buyer_origin=None,
         buyer_origin_id=None,
         buyer_id=None,
         attributes=None,
         requirements=None):
     return Bid(123,
                pendulum.now(),
                price,
                energy,
                buyer,
                original_bid_price,
                buyer_origin=buyer_origin,
                buyer_origin_id=buyer_origin_id,
                buyer_id=buyer_id,
                attributes=attributes,
                requirements=requirements)
Пример #18
0
    def bid(self, price: float, energy: float, buyer: str, seller: str,
            bid_id: str = None, original_bid_price=None, buyer_origin=None,
            adapt_price_with_fees=True):
        self.bid_call_count += 1

        if original_bid_price is None:
            original_bid_price = price

        if bid_id is None:
            bid_id = "uuid"

        if adapt_price_with_fees:
            price = self._update_new_bid_price_with_fee(price, original_bid_price)

        bid = Bid(bid_id, pendulum.now(), price, energy, buyer, seller,
                  original_bid_price=original_bid_price,
                  buyer_origin=buyer_origin)
        self._bids.append(bid)
        self.forwarded_bid = bid

        return bid
Пример #19
0
 def bid(self,
         price: float,
         energy: float,
         buyer: str,
         original_bid_price=None,
         buyer_origin=None,
         buyer_origin_id=None,
         buyer_id=None,
         attributes=None,
         requirements=None) -> Bid:
     bid = Bid(id="bid_id",
               time=now(),
               price=price,
               energy=energy,
               buyer=buyer,
               original_bid_price=original_bid_price,
               buyer_origin=buyer_origin,
               buyer_origin_id=buyer_origin_id,
               buyer_id=buyer_id,
               attributes=attributes,
               requirements=requirements)
     self.bids[bid.id] = bid
     return bid
Пример #20
0
def test_double_sided_market_performs_pay_as_clear_matching(pac_market, offer, bid, mcp_rate,
                                                            mcp_energy, algorithm):
    ConstSettings.IAASettings.PAY_AS_CLEAR_AGGREGATION_ALGORITHM = algorithm
    pac_market.offers = {"offer1": Offer('id1', now(), offer[0], 1, 'other'),
                         "offer2": Offer('id2', now(), offer[1], 1, 'other'),
                         "offer3": Offer('id3', now(), offer[2], 1, 'other'),
                         "offer4": Offer('id4', now(), offer[3], 1, 'other'),
                         "offer5": Offer('id5', now(), offer[4], 1, 'other'),
                         "offer6": Offer('id6', now(), offer[5], 1, 'other'),
                         "offer7": Offer('id7', now(), offer[6], 1, 'other')}

    pac_market.bids = {"bid1": Bid('bid_id1', now(), bid[0], 1, 'B', 'S'),
                       "bid2": Bid('bid_id2', now(), bid[1], 1, 'B', 'S'),
                       "bid3": Bid('bid_id3', now(), bid[2], 1, 'B', 'S'),
                       "bid4": Bid('bid_id4', now(), bid[3], 1, 'B', 'S'),
                       "bid5": Bid('bid_id5', now(), bid[4], 1, 'B', 'S'),
                       "bid6": Bid('bid_id6', now(), bid[5], 1, 'B', 'S'),
                       "bid7": Bid('bid_id7', now(), bid[6], 1, 'B', 'S')}

    matched_rate, matched_energy = pac_market._perform_pay_as_clear_matching()
    assert matched_rate == mcp_rate
    assert matched_energy == mcp_energy
Пример #21
0
def test_iaa_double_sided_performs_pay_as_clear_matching(iaa_double_sided_pay_as_clear,
                                                         offer, bid, MCP):
    low_high_engine = \
        next(filter(lambda e: e.name == "Low -> High", iaa_double_sided_pay_as_clear.engines))
    iaa_double_sided_pay_as_clear.lower_market.sorted_offers = \
        [Offer('id1', offer[0], 1, 'other'),
         Offer('id2', offer[1], 1, 'other'),
         Offer('id3', offer[2], 1, 'other'),
         Offer('id4', offer[3], 1, 'other'),
         Offer('id5', offer[4], 1, 'other'),
         Offer('id6', offer[5], 1, 'other'),
         Offer('id7', offer[6], 1, 'other')]

    iaa_double_sided_pay_as_clear.lower_market._bids = \
        [Bid('bid_id1', bid[0], 1, 'B', 'S'),
         Bid('bid_id2', bid[1], 1, 'B', 'S'),
         Bid('bid_id3', bid[2], 1, 'B', 'S'),
         Bid('bid_id4', bid[3], 1, 'B', 'S'),
         Bid('bid_id5', bid[4], 1, 'B', 'S'),
         Bid('bid_id6', bid[5], 1, 'B', 'S'),
         Bid('bid_id7', bid[6], 1, 'B', 'S')]

    matched = low_high_engine._perform_pay_as_clear_matching()[0]
    assert matched == MCP
Пример #22
0
 def bid(self, price: float, energy: float, buyer: str, seller: str, bid_id: str=None) -> Bid:
     bid = Bid(id='bid_id', price=price, energy=energy, buyer=buyer, seller=seller)
     self.bids[bid.id] = bid
     return bid
Пример #23
0
def test_device_operating_hours_deduction_with_partial_trade(
        load_hours_strategy_test5, market_test2):
    market_test2.most_affordable_energy = 0.1
    load_hours_strategy_test5.event_activate()
    # load_hours_strategy_test5.area.past_markets = {TIME: market_test2}
    load_hours_strategy_test5.event_market_cycle()
    load_hours_strategy_test5.event_tick()
    assert round(((float(load_hours_strategy_test5.accept_offer.call_args[0][1].energy) *
                   1000 / load_hours_strategy_test5.energy_per_slot_Wh) *
                  (load_hours_strategy_test5.area.config.slot_length / duration(hours=1))), 2) == \
        round(((0.1/0.155) * 0.25), 2)


@pytest.mark.parametrize("partial",
                         [None, Bid('test_id', now(), 123, 321, 'A')])
def test_event_bid_traded_removes_bid_for_partial_and_non_trade(
        load_hours_strategy_test5, called, partial):
    ConstSettings.IAASettings.MARKET_TYPE = 2

    trade_market = load_hours_strategy_test5.area.next_market
    load_hours_strategy_test5.remove_bid_from_pending = called
    load_hours_strategy_test5.event_activate()
    load_hours_strategy_test5.area.markets = {TIME: trade_market}
    load_hours_strategy_test5.event_market_cycle()
    # Get the bid that was posted on event_market_cycle
    bid = list(load_hours_strategy_test5._bids.values())[0][0]

    # Increase energy requirement to cover the energy from the bid
    load_hours_strategy_test5.state._energy_requirement_Wh[TIME] = 1000
    trade = Trade('idt',
Пример #24
0
    def accept_bid(self,
                   bid: Bid,
                   energy: float = None,
                   seller: str = None,
                   buyer: str = None,
                   already_tracked: bool = False,
                   trade_rate: float = None,
                   trade_offer_info=None,
                   seller_origin=None):
        market_bid = self.bids.pop(bid.id, None)
        if market_bid is None:
            raise BidNotFound("During accept bid: " + str(bid))

        seller = market_bid.seller if seller is None else seller
        buyer = market_bid.buyer if buyer is None else buyer
        energy = market_bid.energy if energy is None else energy

        orig_price = bid.original_bid_price if bid.original_bid_price is not None else bid.price
        residual_bid = None

        if energy <= 0:
            raise InvalidTrade("Energy cannot be negative or zero.")
        elif energy > market_bid.energy:
            raise InvalidTrade(
                "Traded energy cannot be more than the bid energy.")
        elif energy < market_bid.energy:
            # partial bid trade
            accepted_bid, residual_bid = self.split_bid(
                market_bid, energy, orig_price)
            bid = accepted_bid

            # Delete the accepted bid from self.bids:
            try:
                self.bids.pop(accepted_bid.id)
            except KeyError:
                raise BidNotFound(
                    f"Bid {accepted_bid.id} not found in self.bids ({self.name})."
                )
        else:
            # full bid trade, nothing further to do here
            pass

        fee_price, trade_price = self.determine_bid_price(
            trade_offer_info, energy)
        bid = bid._replace(price=trade_price)

        # Do not adapt grid fees when creating the bid_trade_info structure, to mimic
        # the behavior of the forwarded bids which use the source market fee.
        updated_bid_trade_info = self.fee_class.propagate_original_offer_info_on_bid_trade(
            trade_offer_info, ignore_fees=True)

        trade = Trade(str(uuid.uuid4()),
                      self.now,
                      bid,
                      seller,
                      buyer,
                      residual_bid,
                      already_tracked=already_tracked,
                      offer_bid_trade_info=updated_bid_trade_info,
                      buyer_origin=bid.buyer_origin,
                      seller_origin=seller_origin,
                      fee_price=fee_price)

        if already_tracked is False:
            self._update_stats_after_trade(trade, bid, bid.buyer,
                                           already_tracked)
            log.info(
                f"[TRADE][BID] [{self.name}] [{self.time_slot_str}] {trade}")

        self._notify_listeners(MarketEvent.BID_TRADED, bid_trade=trade)
        return trade
Пример #25
0
def test_offer_id_stringified():
    bid = Bid(object(), pendulum.now(), 10, 20, 'A', 'B')

    assert isinstance(bid.id, str)
    assert "<object object at" in bid.id
Пример #26
0
def test_device_operating_hours_deduction_with_partial_trade(
        load_hours_strategy_test5, market_test2):
    market_test2.most_affordable_energy = 0.1
    load_hours_strategy_test5.event_activate()
    # load_hours_strategy_test5.area.past_markets = {TIME: market_test2}
    load_hours_strategy_test5.event_market_cycle()
    load_hours_strategy_test5.event_tick()
    assert round(((float(load_hours_strategy_test5.accept_offer.call_args[0][1].energy) *
                   1000 / load_hours_strategy_test5.energy_per_slot_Wh) *
                  (load_hours_strategy_test5.area.config.slot_length / duration(hours=1))), 2) == \
        round(((0.1/0.155) * 0.25), 2)


@pytest.mark.parametrize(
    "partial", [None, Bid('test_id', now(), 123, 321, 'A', 'B')])
def test_event_bid_traded_removes_bid_for_partial_and_non_trade(
        load_hours_strategy_test5, called, partial):
    ConstSettings.IAASettings.MARKET_TYPE = 2

    trade_market = load_hours_strategy_test5.area.next_market
    load_hours_strategy_test5.remove_bid_from_pending = called
    load_hours_strategy_test5.event_activate()
    load_hours_strategy_test5.area.markets = {TIME: trade_market}
    load_hours_strategy_test5.event_market_cycle()
    # Get the bid that was posted on event_market_cycle
    bid = list(load_hours_strategy_test5._bids.values())[0][0]

    # Increase energy requirement to cover the energy from the bid
    load_hours_strategy_test5.energy_requirement_Wh[TIME] = 1000
    trade = Trade('idt',

def test_device_operating_hours_deduction_with_partial_trade(
        load_hours_strategy_test5, market_test2):
    market_test2.most_affordable_energy = 0.1
    load_hours_strategy_test5.event_activate()
    # load_hours_strategy_test5.area.past_markets = {TIME: market_test2}
    load_hours_strategy_test5.event_market_cycle()
    load_hours_strategy_test5.event_tick()
    assert round(((float(load_hours_strategy_test5.accept_offer.call_args[0][1].energy) *
                   1000 / load_hours_strategy_test5.energy_per_slot_Wh) *
                  (load_hours_strategy_test5.area.config.slot_length / duration(hours=1))), 2) == \
        round(((0.1/0.155) * 0.25), 2)


@pytest.mark.parametrize("partial", [None, Bid('test_id', 123, 321, 'A', 'B')])
def test_event_bid_traded_removes_bid_for_partial_and_non_trade(
        load_hours_strategy_test5, called, partial):
    ConstSettings.IAASettings.MARKET_TYPE = 2

    trade_market = load_hours_strategy_test5.area.next_market
    load_hours_strategy_test5.remove_bid_from_pending = called
    load_hours_strategy_test5.event_activate()
    load_hours_strategy_test5.area.markets = {TIME: trade_market}
    load_hours_strategy_test5.event_market_cycle()
    load_hours_strategy_test5.event_tick()
    # Get the bid that was posted on event_market_cycle
    bid = list(load_hours_strategy_test5._bids.values())[0][0]

    # Increase energy requirement to cover the energy from the bid
    load_hours_strategy_test5.energy_requirement_Wh[TIME] = 1000
Пример #28
0
 def bid(self, price, energy, buyer, seller):
     return Bid(123, price, energy, buyer, seller, self)
Пример #29
0
    def accept_bid(self, bid: Bid, energy: float = None,
                   seller: str = None, buyer: str = None, already_tracked: bool = False,
                   trade_rate: float = None, trade_offer_info=None, seller_origin=None):
        market_bid = self.bids.pop(bid.id, None)
        if market_bid is None:
            raise BidNotFound("During accept bid: " + str(bid))

        seller = market_bid.seller if seller is None else seller
        buyer = market_bid.buyer if buyer is None else buyer
        energy = market_bid.energy if energy is None else energy
        if trade_rate is None:
            trade_rate = market_bid.price / market_bid.energy

        assert trade_rate <= (market_bid.price / market_bid.energy) + FLOATING_POINT_TOLERANCE, \
            f"trade rate: {trade_rate} market {market_bid.price / market_bid.energy}"

        orig_price = bid.original_bid_price if bid.original_bid_price is not None else bid.price
        residual = None

        if energy <= 0:
            raise InvalidTrade("Energy cannot be negative or zero.")
        elif energy > market_bid.energy:
            raise InvalidTrade("Traded energy cannot be more than the bid energy.")
        elif energy < market_bid.energy:
            # Partial bidding
            energy_portion = energy / market_bid.energy
            residual_price = (1 - energy_portion) * market_bid.price
            residual_energy = market_bid.energy - energy

            # Manually creating the bid in order to not double-charge the fee of the
            # residual bid
            changed_bid = Bid(
                str(uuid.uuid4()), residual_price, residual_energy,
                buyer, seller,
                original_bid_price=(1 - energy_portion) * orig_price,
                buyer_origin=market_bid.buyer_origin
            )

            self.bids[changed_bid.id] = changed_bid
            self.bid_history.append(changed_bid)

            self._notify_listeners(MarketEvent.BID_CHANGED,
                                   existing_bid=bid, new_bid=changed_bid)
            residual = changed_bid

            revenue, fees, final_trade_rate = GridFees.calculate_trade_price_and_fees(
                trade_offer_info, self.transfer_fee_ratio
            )
            self.market_fee += fees
            final_price = energy * final_trade_rate
            bid = Bid(bid.id, final_price, energy, buyer, seller,
                      original_bid_price=energy_portion * orig_price,
                      buyer_origin=bid.buyer_origin)
        else:
            revenue, fees, final_trade_rate = GridFees.calculate_trade_price_and_fees(
                trade_offer_info, self.transfer_fee_ratio
            )
            self.market_fee += fees
            final_price = energy * final_trade_rate
            bid = bid._replace(price=final_price)

        trade = Trade(str(uuid.uuid4()), self._now, bid, seller,
                      buyer, residual, already_tracked=already_tracked,
                      offer_bid_trade_info=GridFees.propagate_original_offer_info_on_bid_trade(
                          trade_offer_info, self.transfer_fee_ratio),
                      buyer_origin=bid.buyer_origin, seller_origin=seller_origin
                      )

        if already_tracked is False:
            self._update_stats_after_trade(trade, bid, bid.buyer, already_tracked)
            log.info(f"[TRADE][BID] [{self.time_slot_str}] {trade}")
            final_bid = bid._replace(price=final_price)
            trade = trade._replace(offer=final_bid)

        self._notify_listeners(MarketEvent.BID_TRADED, bid_trade=trade)
        if not trade.residual:
            self._notify_listeners(MarketEvent.BID_DELETED, bid=market_bid)
        return trade
Пример #30
0
 def bid(self, price, energy, buyer, seller):
     self.bid_count += 1
     self.forwarded_bid = Bid(self.forwarded_bid_id, price, energy, buyer, seller, market=self)
     return self.forwarded_bid