diff --git a/src/functional/java/org/economicsl/auctions/ImperativePeriodicDoubleAuction.java b/src/functional/java/org/economicsl/auctions/ImperativePeriodicDoubleAuction.java index e260d33..6976e4c 100644 --- a/src/functional/java/org/economicsl/auctions/ImperativePeriodicDoubleAuction.java +++ b/src/functional/java/org/economicsl/auctions/ImperativePeriodicDoubleAuction.java @@ -1,10 +1,10 @@ package org.economicsl.auctions; -import org.economicsl.auctions.OrderTracker.*; -import org.economicsl.auctions.singleunit.OpenBidAuction; -import org.economicsl.auctions.singleunit.OrderGenerator; -import org.economicsl.auctions.singleunit.orders.Order; +import org.economicsl.auctions.participants.OrderGenerator; +import org.economicsl.auctions.participants.OrderTracker.*; +import org.economicsl.auctions.singleunit.OpenBidSingleUnitAuction; +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder; import org.economicsl.auctions.singleunit.pricing.MidPointPricingPolicy; import scala.Option; @@ -27,23 +27,23 @@ public static void main(String[] args) { // define the auction mechanism... TestStock googleStock = new TestStock(); MidPointPricingPolicy midpointPricingPolicy = new MidPointPricingPolicy<>(); - OpenBidAuction doubleAuction = OpenBidAuction.withUniformClearingPolicy(midpointPricingPolicy, googleStock); + OpenBidSingleUnitAuction doubleAuction = OpenBidSingleUnitAuction.withUniformClearingPolicy(midpointPricingPolicy, googleStock); // generate some random order flow... int numberOrders = 10000; Random prng = new Random(42); - Stream>> orders = OrderGenerator.randomOrders(0.5, numberOrders, googleStock, prng); + Stream>> orders = OrderGenerator.randomOrders(0.5, numberOrders, googleStock, prng); List> insertResults = new ArrayList<>(); - for (Tuple2> order:JavaConverters.seqAsJavaList(orders)) { - Tuple2, Either> insertResult = doubleAuction.insert(order); + for (Tuple2> order:JavaConverters.seqAsJavaList(orders)) { + Tuple2, Either> insertResult = doubleAuction.insert(order); doubleAuction = insertResult._1(); insertResults.add(insertResult._2()); } // clear the auction... - Tuple2, Option>> results = doubleAuction.clear(); + Tuple2, Option>> results = doubleAuction.clear(); List fills = JavaConverters.seqAsJavaList(results._2().get()); // print the results to console... diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/AuctionSimulation.scala b/src/functional/scala/org/economicsl/auctions/singleunit/AuctionSimulation.scala index 04a8a14..93f30c3 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/AuctionSimulation.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/AuctionSimulation.scala @@ -1,16 +1,16 @@ package org.economicsl.auctions.singleunit -import org.economicsl.auctions.OrderTracker.{Accepted, Rejected} -import org.economicsl.auctions.Token -import org.economicsl.auctions.singleunit.orders.Order +import org.economicsl.auctions.participants.OrderTracker.{Accepted, Rejected} +import org.economicsl.auctions.participants.Token +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder import org.economicsl.core.Tradable trait AuctionSimulation { - type InsertResult[T <: Tradable, A <: Auction[T, A]] = (A, Stream[Either[Rejected, Accepted]]) + type InsertResult[T <: Tradable, A <: SingleUnitAuction[T, A]] = (A, Stream[Either[Rejected, Accepted]]) - def insert[T <: Tradable, A <: Auction[T, A]](initial: A)(orders: Stream[(Token, Order[T])]): (A, Stream[Either[Rejected, Accepted]]) = { + def insert[T <: Tradable, A <: SingleUnitAuction[T, A]](initial: A)(orders: Stream[(Token, SingleUnitOrder[T])]): (A, Stream[Either[Rejected, Accepted]]) = { orders.foldLeft((initial, Stream.empty[Either[Rejected, Accepted]])) { case ((auction, insertResults), order) => val (updated, insertResult) = auction.insert(order) diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/ContinuousDoubleAuction.scala b/src/functional/scala/org/economicsl/auctions/singleunit/ContinuousDoubleAuction.scala index aa493d3..acab32f 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/ContinuousDoubleAuction.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/ContinuousDoubleAuction.scala @@ -16,8 +16,9 @@ limitations under the License. package org.economicsl.auctions.singleunit import org.economicsl.auctions._ +import org.economicsl.auctions.participants.{OrderGenerator, Token} import org.economicsl.auctions.quotes._ -import org.economicsl.auctions.singleunit.orders.Order +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder import org.economicsl.auctions.singleunit.pricing.MidPointPricingPolicy import org.economicsl.core.{Price, Tradable} @@ -33,15 +34,15 @@ object ContinuousDoubleAuction extends App { val google: TestStock = TestStock() val pricingRule = new MidPointPricingPolicy[TestStock] - val withDiscriminatoryPricing = OpenBidAuction.withDiscriminatoryClearingPolicy(pricingRule, google) + val withDiscriminatoryPricing = OpenBidSingleUnitAuction.withDiscriminatoryClearingPolicy(pricingRule, google) // generate a very large stream of random orders... - type OrderFlow[T <: Tradable] = Stream[(Token, Order[T])] + type OrderFlow[T <: Tradable] = Stream[(Token, SingleUnitOrder[T])] val prng = new Random(42) val orders: OrderFlow[TestStock] = OrderGenerator.randomOrders(0.5)(1000000, google, prng) // A lazy, tail-recursive implementation of a continuous double auction! - def continuous[T <: Tradable, A <: Auction[T, A]](auction: A)(incoming: OrderFlow[T]): Stream[(A, Option[Stream[SpotContract]])] = { + def continuous[T <: Tradable, A <: SingleUnitAuction[T, A]](auction: A)(incoming: OrderFlow[T]): Stream[(A, Option[Stream[SpotContract]])] = { @annotation.tailrec def loop(da: A, in: OrderFlow[T], out: Stream[(A, Option[Stream[SpotContract]])]): Stream[(A, Option[Stream[SpotContract]])] = in match { case Stream.Empty => out @@ -57,7 +58,7 @@ object ContinuousDoubleAuction extends App { * containing the unmatched orders following each clear. Basically the entire auction history is stored in the * stream of clear results. */ - val results = continuous[TestStock, OpenBidAuction[TestStock]](withDiscriminatoryPricing)(orders) + val results = continuous[TestStock, OpenBidSingleUnitAuction[TestStock]](withDiscriminatoryPricing)(orders) val prices: Stream[Price] = results.flatMap{ case (_, fills) => fills.flatMap(_.headOption).map(_.price) diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceOpenBidAuctionSpec.scala b/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceOpenBidAuctionSpec.scala index 76cbcb9..bbaa342 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceOpenBidAuctionSpec.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceOpenBidAuctionSpec.scala @@ -21,6 +21,7 @@ import org.economicsl.auctions.quotes.AskPriceQuoteRequest import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder} import org.economicsl.auctions.singleunit.pricing.AskQuotePricingPolicy import org.economicsl.auctions._ +import org.economicsl.auctions.participants.{OrderGenerator, Token, TokenGenerator} import org.economicsl.core.Price import org.scalatest.{FlatSpec, Matchers} @@ -47,8 +48,8 @@ class FirstPriceOpenBidAuctionSpec val (_, highestPricedBidOrder) = bidOrders.maxBy{ case (_, bidOrder) => bidOrder.limit } // seller uses a first-priced, open bid auction... - val firstPriceOpenBidAuction: OpenBidAuction[ParkingSpace] = { - OpenBidAuction.withUniformClearingPolicy(AskQuotePricingPolicy[ParkingSpace], parkingSpace) + val firstPriceOpenBidAuction: OpenBidSingleUnitAuction[ParkingSpace] = { + OpenBidSingleUnitAuction.withUniformClearingPolicy(AskQuotePricingPolicy[ParkingSpace], parkingSpace) } // Seller that must sell at any positive price @@ -58,7 +59,7 @@ class FirstPriceOpenBidAuctionSpec val (withReservationAskOrder, _) = firstPriceOpenBidAuction.insert(reservation) // withBidOrders will include all accepted bids (this is trivially parallel..) - val (withBidOrders, _) = insert[ParkingSpace, OpenBidAuction[ParkingSpace]](withReservationAskOrder)(bidOrders) + val (withBidOrders, _) = insert[ParkingSpace, OpenBidSingleUnitAuction[ParkingSpace]](withReservationAskOrder)(bidOrders) val (clearedAuction, clearResults) = withBidOrders.clear "A First-Price, Open-Bid Auction (FPOBA)" should "be able to process ask price quote requests" in { diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidAuctionSpec.scala b/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidAuctionSpec.scala index 80830b9..61eef5d 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidAuctionSpec.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidAuctionSpec.scala @@ -17,10 +17,11 @@ package org.economicsl.auctions.singleunit import java.util.UUID -import org.economicsl.auctions.OrderTracker.{Accepted, Rejected} +import org.economicsl.auctions.participants.OrderTracker.{Accepted, Rejected} import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder} import org.economicsl.auctions.singleunit.pricing.AskQuotePricingPolicy import org.economicsl.auctions._ +import org.economicsl.auctions.participants.{OrderGenerator, Token, TokenGenerator} import org.economicsl.core.Price import org.scalatest.{FlatSpec, Matchers} @@ -40,8 +41,8 @@ class FirstPriceSealedBidAuctionSpec // seller uses a first-priced, sealed bid auction... val uuid: UUID = UUID.randomUUID() val parkingSpace = ParkingSpace(uuid) - val firstPriceSealedBidAuction: SealedBidAuction[ParkingSpace] = { - SealedBidAuction.withUniformClearingPolicy(AskQuotePricingPolicy[ParkingSpace], parkingSpace) + val firstPriceSealedBidAuction: SealedBidSingleUnitAuction[ParkingSpace] = { + SealedBidSingleUnitAuction.withUniformClearingPolicy(AskQuotePricingPolicy[ParkingSpace], parkingSpace) } // suppose that seller must sell the parking space at any positive price... diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidReverseAuctionSpec.scala b/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidReverseAuctionSpec.scala index 02697e2..e295ab3 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidReverseAuctionSpec.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/FirstPriceSealedBidReverseAuctionSpec.scala @@ -17,10 +17,11 @@ package org.economicsl.auctions.singleunit import java.util.UUID -import org.economicsl.auctions.OrderTracker.{Accepted, Rejected} -import org.economicsl.auctions.singleunit.orders.{BidOrder, LimitAskOrder, LimitBidOrder} +import org.economicsl.auctions.participants.{OrderGenerator, Token} +import org.economicsl.auctions.participants.OrderTracker.{Accepted, Rejected} +import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder, SingleUnitBidOrder} import org.economicsl.auctions.singleunit.pricing.BidQuotePricingPolicy -import org.economicsl.auctions.{Issuer, Seller, Service, Token} +import org.economicsl.auctions.{Issuer, Seller, Service} import org.economicsl.core.Price import org.scalatest.{FlatSpec, Matchers} @@ -38,14 +39,14 @@ class FirstPriceSealedBidReverseAuctionSpec // reverse auction to procure a service at lowest possible cost... val service = Service() - val firstPriceSealedBidReverseAuction: SealedBidAuction[Service] = { - SealedBidAuction.withUniformClearingPolicy(BidQuotePricingPolicy[Service], service) + val firstPriceSealedBidReverseAuction: SealedBidSingleUnitAuction[Service] = { + SealedBidSingleUnitAuction.withUniformClearingPolicy(BidQuotePricingPolicy[Service], service) } // buyer is willing to pay anything... val buyer: Issuer = UUID.randomUUID() val buyersToken: Token = UUID.randomUUID() - val reservationBidOrder: (Token, BidOrder[Service]) = (buyersToken, LimitBidOrder(buyer, Price.MaxValue, service)) + val reservationBidOrder: (Token, SingleUnitBidOrder[Service]) = (buyersToken, LimitBidOrder(buyer, Price.MaxValue, service)) val (withReservationBidOrder, _) = firstPriceSealedBidReverseAuction.insert(reservationBidOrder) // generate some random sellers... @@ -55,7 +56,7 @@ class FirstPriceSealedBidReverseAuctionSpec val (_, lowestPricedAskOrder): (Token, LimitAskOrder[Service]) = offers.minBy{ case (_, askOrder) => askOrder.limit } // insert the ask orders into the auction mechanism...can be done in parallel! - val (withAskOrders, _): (SealedBidAuction[Service], Stream[Either[Rejected, Accepted]]) = { + val (withAskOrders, _): (SealedBidSingleUnitAuction[Service], Stream[Either[Rejected, Accepted]]) = { offers.foldLeft((withReservationBidOrder, Stream.empty[Either[Rejected, Accepted]])) { case ((auction, insertResults), askOrder) => val (updatedAuction, insertResult) = auction.insert(askOrder) diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/PeriodicDoubleAuction.scala b/src/functional/scala/org/economicsl/auctions/singleunit/PeriodicDoubleAuction.scala index 56e8dcd..9ee2542 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/PeriodicDoubleAuction.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/PeriodicDoubleAuction.scala @@ -15,9 +15,10 @@ limitations under the License. */ package org.economicsl.auctions.singleunit -import org.economicsl.auctions.OrderTracker.{Accepted, Rejected} -import org.economicsl.auctions.{TestStock, Token} -import org.economicsl.auctions.singleunit.orders.Order +import org.economicsl.auctions.participants.{OrderGenerator, Token} +import org.economicsl.auctions.participants.OrderTracker.{Accepted, Rejected} +import org.economicsl.auctions.TestStock +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder import org.economicsl.auctions.singleunit.pricing.MidPointPricingPolicy import org.scalatest.{FlatSpec, Matchers} @@ -36,12 +37,12 @@ class PeriodicDoubleAuction // generate a stream of random orders... val google: TestStock = TestStock() val prng = new Random(42) - val orders: Stream[(Token, Order[TestStock])] = OrderGenerator.randomOrders(0.5)(100, google, prng) + val orders: Stream[(Token, SingleUnitOrder[TestStock])] = OrderGenerator.randomOrders(0.5)(100, google, prng) "A PeriodicDoubleAuction with uniform pricing" should "produce a single price at which all filled orders are processed." in { val pricingRule = new MidPointPricingPolicy[TestStock] - val withUniformPricing = SealedBidAuction.withUniformClearingPolicy(pricingRule, google) + val withUniformPricing = SealedBidSingleUnitAuction.withUniformClearingPolicy(pricingRule, google) // this whole process is data parallel... val (withOrders, _) = { diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceOpenBidAuctionSpec.scala b/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceOpenBidAuctionSpec.scala index 7083aff..1f09e61 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceOpenBidAuctionSpec.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceOpenBidAuctionSpec.scala @@ -17,8 +17,9 @@ package org.economicsl.auctions.singleunit import java.util.UUID -import org.economicsl.auctions.OrderTracker.{Accepted, Rejected} +import org.economicsl.auctions.participants.OrderTracker.{Accepted, Rejected} import org.economicsl.auctions._ +import org.economicsl.auctions.participants.{OrderGenerator, Token} import org.economicsl.auctions.quotes.AskPriceQuoteRequest import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder} import org.economicsl.auctions.singleunit.pricing.BidQuotePricingPolicy @@ -41,8 +42,8 @@ class SecondPriceOpenBidAuctionSpec val tickSize: Currency = 1 val uuid: UUID = UUID.randomUUID() val parkingSpace = ParkingSpace(uuid) - val secondPriceOpenBidAuction: OpenBidAuction[ParkingSpace] = { - OpenBidAuction.withUniformClearingPolicy(BidQuotePricingPolicy[ParkingSpace], tickSize, parkingSpace) + val secondPriceOpenBidAuction: OpenBidSingleUnitAuction[ParkingSpace] = { + OpenBidSingleUnitAuction.withUniformClearingPolicy(BidQuotePricingPolicy[ParkingSpace], tickSize, parkingSpace) } val seller: UUID = UUID.randomUUID() @@ -62,7 +63,7 @@ class SecondPriceOpenBidAuctionSpec val (updatedAuction, result) = auction.insert(bidOrder) (updatedAuction, result #:: results) } - val (clearedAuction, fills): (OpenBidAuction[ParkingSpace], Option[Stream[SpotContract]]) = withBidOrders.clear + val (clearedAuction, fills): (OpenBidSingleUnitAuction[ParkingSpace], Option[Stream[SpotContract]]) = withBidOrders.clear "A Second-Price, Open-Bid Auction (SPOBA)" should "be able to process ask price quote requests" in { diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidAuctionSpec.scala b/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidAuctionSpec.scala index cc0fb52..ece04e7 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidAuctionSpec.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidAuctionSpec.scala @@ -17,8 +17,9 @@ package org.economicsl.auctions.singleunit import java.util.UUID -import org.economicsl.auctions.OrderTracker.{Accepted, Rejected} +import org.economicsl.auctions.participants.OrderTracker.{Accepted, Rejected} import org.economicsl.auctions._ +import org.economicsl.auctions.participants.{OrderGenerator, Token, TokenGenerator} import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder} import org.economicsl.auctions.singleunit.pricing.BidQuotePricingPolicy import org.economicsl.core.{Currency, Price} @@ -41,8 +42,8 @@ class SecondPriceSealedBidAuctionSpec val tickSize: Currency = 1 val uuid: UUID = UUID.randomUUID() val parkingSpace = ParkingSpace(uuid) - val secondPriceSealedBidAuction: SealedBidAuction[ParkingSpace] = { - SealedBidAuction.withUniformClearingPolicy(BidQuotePricingPolicy[ParkingSpace], tickSize, parkingSpace) + val secondPriceSealedBidAuction: SealedBidSingleUnitAuction[ParkingSpace] = { + SealedBidSingleUnitAuction.withUniformClearingPolicy(BidQuotePricingPolicy[ParkingSpace], tickSize, parkingSpace) } val seller: UUID = UUID.randomUUID() @@ -62,7 +63,7 @@ class SecondPriceSealedBidAuctionSpec (updatedAuction, result #:: results) } - val (clearedAuction, fills): (SealedBidAuction[ParkingSpace], Option[Stream[SpotContract]]) = withBidOrders.clear + val (clearedAuction, fills): (SealedBidSingleUnitAuction[ParkingSpace], Option[Stream[SpotContract]]) = withBidOrders.clear "A Second-Price, Sealed-Bid Auction (SPSBA)" should "allocate the Tradable to the bidder that submitted the bid with the highest price." in { diff --git a/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidReverseAuctionSpec.scala b/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidReverseAuctionSpec.scala index d01b8b9..9a6b521 100644 --- a/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidReverseAuctionSpec.scala +++ b/src/functional/scala/org/economicsl/auctions/singleunit/SecondPriceSealedBidReverseAuctionSpec.scala @@ -17,11 +17,11 @@ package org.economicsl.auctions.singleunit import java.util.UUID - -import org.economicsl.auctions.OrderTracker.{Accepted, Rejected} -import org.economicsl.auctions.singleunit.orders.{BidOrder, LimitAskOrder, LimitBidOrder} +import org.economicsl.auctions.participants.{OrderGenerator, Token} +import org.economicsl.auctions.participants.OrderTracker.{Accepted, Rejected} +import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder, SingleUnitBidOrder} import org.economicsl.auctions.singleunit.pricing.AskQuotePricingPolicy -import org.economicsl.auctions.{Issuer, Seller, Service, Token} +import org.economicsl.auctions.{Issuer, Seller, Service} import org.economicsl.core.Price import org.scalatest.{FlatSpec, Matchers} @@ -39,14 +39,14 @@ class SecondPriceSealedBidReverseAuctionSpec // reverse auction to procure a service at lowest possible cost... val service = Service() - val secondPriceSealedBidReverseAuction: SealedBidAuction[Service] = { - SealedBidAuction.withUniformClearingPolicy(AskQuotePricingPolicy[Service], service) + val secondPriceSealedBidReverseAuction: SealedBidSingleUnitAuction[Service] = { + SealedBidSingleUnitAuction.withUniformClearingPolicy(AskQuotePricingPolicy[Service], service) } // buyer is willing to pay anything... val buyer: Issuer = UUID.randomUUID() val buyersToken: Token = UUID.randomUUID() - val reservationBidOrder: (Token, BidOrder[Service]) = (buyersToken, LimitBidOrder(buyer, Price.MaxValue, service)) + val reservationBidOrder: (Token, SingleUnitBidOrder[Service]) = (buyersToken, LimitBidOrder(buyer, Price.MaxValue, service)) val (withReservationBidOrder, _) = secondPriceSealedBidReverseAuction.insert(reservationBidOrder) // generate some random sellers... @@ -56,7 +56,7 @@ class SecondPriceSealedBidReverseAuctionSpec val (_, lowestPricedAskOrder): (Token, LimitAskOrder[Service]) = offers.minBy{ case (_, order) => order.limit } // insert the ask orders into the auction mechanism...can be done in parallel! - val (withAskOrders, _): (SealedBidAuction[Service], Stream[Either[Rejected, Accepted]]) = { + val (withAskOrders, _): (SealedBidSingleUnitAuction[Service], Stream[Either[Rejected, Accepted]]) = { offers.foldLeft((withReservationBidOrder, Stream.empty[Either[Rejected, Accepted]])) { case ((auction, insertResults), askOrder) => val (updatedAuction, insertResult) = auction.insert(askOrder) diff --git a/src/main/java/org/economicsl/auctions/singleunit/CancelResult.java b/src/main/java/org/economicsl/auctions/singleunit/CancelResult.java index aca31b1..367f7e2 100644 --- a/src/main/java/org/economicsl/auctions/singleunit/CancelResult.java +++ b/src/main/java/org/economicsl/auctions/singleunit/CancelResult.java @@ -16,7 +16,7 @@ package org.economicsl.auctions.singleunit; -import org.economicsl.auctions.OrderTracker.*; +import org.economicsl.auctions.participants.OrderTracker.*; import scala.Option; diff --git a/src/main/java/org/economicsl/auctions/singleunit/InsertResult.java b/src/main/java/org/economicsl/auctions/singleunit/InsertResult.java index 99d55bc..8aba686 100644 --- a/src/main/java/org/economicsl/auctions/singleunit/InsertResult.java +++ b/src/main/java/org/economicsl/auctions/singleunit/InsertResult.java @@ -16,7 +16,7 @@ package org.economicsl.auctions.singleunit; -import org.economicsl.auctions.OrderTracker.*; +import org.economicsl.auctions.participants.OrderTracker.*; import scala.util.Either; diff --git a/src/main/java/org/economicsl/auctions/singleunit/JAuction.java b/src/main/java/org/economicsl/auctions/singleunit/JAuction.java index 93c7151..623cb36 100644 --- a/src/main/java/org/economicsl/auctions/singleunit/JAuction.java +++ b/src/main/java/org/economicsl/auctions/singleunit/JAuction.java @@ -1,7 +1,7 @@ package org.economicsl.auctions.singleunit; -import org.economicsl.auctions.singleunit.orders.Order; +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder; import org.economicsl.auctions.singleunit.pricing.PricingPolicy; import org.economicsl.core.Tradable; import scala.Tuple2; @@ -31,7 +31,7 @@ public abstract class JAuction> { * @return * @todo get rid of Tuple2 class! */ - public abstract InsertResult insert(Tuple2> order); + public abstract InsertResult insert(Tuple2> order); /** Returns an auction of type `A` with a particular pricing policy. */ public abstract A withPricingPolicy(PricingPolicy updated); diff --git a/src/main/java/org/economicsl/auctions/singleunit/JOpenBidAuction.java b/src/main/java/org/economicsl/auctions/singleunit/JOpenBidAuction.java index e08ca57..4650f97 100644 --- a/src/main/java/org/economicsl/auctions/singleunit/JOpenBidAuction.java +++ b/src/main/java/org/economicsl/auctions/singleunit/JOpenBidAuction.java @@ -16,11 +16,11 @@ package org.economicsl.auctions.singleunit; -import org.economicsl.auctions.OrderTracker.*; +import org.economicsl.auctions.participants.OrderTracker.*; import org.economicsl.auctions.SpotContract; import org.economicsl.auctions.quotes.Quote; import org.economicsl.auctions.quotes.QuoteRequest; -import org.economicsl.auctions.singleunit.orders.Order; +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder; import org.economicsl.auctions.singleunit.pricing.PricingPolicy; import org.economicsl.core.Tradable; import scala.Option; @@ -37,9 +37,9 @@ */ class JOpenBidAuction extends JAuction> { - private OpenBidAuction auction; + private OpenBidSingleUnitAuction auction; - private JOpenBidAuction(OpenBidAuction auction) { + private JOpenBidAuction(OpenBidSingleUnitAuction auction) { this.auction = auction; } @@ -50,7 +50,7 @@ private JOpenBidAuction(OpenBidAuction auction) { * @return */ public CancelResult> cancel(UUID reference) { - Tuple2, Option> result = auction.cancel(reference); + Tuple2, Option> result = auction.cancel(reference); JOpenBidAuction jAuction = new JOpenBidAuction<>(result._1); return new CancelResult<>(jAuction, result._2); } @@ -60,7 +60,7 @@ public CancelResult> cancel(UUID reference) { * @return an instance of `ClearResult` class. */ public ClearResult> clear() { - Tuple2, Option>> result = auction.clear(); + Tuple2, Option>> result = auction.clear(); JOpenBidAuction jAuction = new JOpenBidAuction<>(result._1); return new ClearResult<>(jAuction, result._2); } @@ -70,8 +70,8 @@ public ClearResult> clear() { * @param order * @return */ - public InsertResult> insert(Tuple2> order) { - Tuple2, Either> result = auction.insert(order); + public InsertResult> insert(Tuple2> order) { + Tuple2, Either> result = auction.insert(order); JOpenBidAuction jAuction = new JOpenBidAuction<>(result._1()); return new InsertResult<>(jAuction, result._2()); } @@ -81,12 +81,12 @@ public Quote receive(QuoteRequest request) { } public JOpenBidAuction withPricingPolicy(PricingPolicy updated) { - OpenBidAuction withUpdatedPricingPolicy = auction.withPricingPolicy(updated); + OpenBidSingleUnitAuction withUpdatedPricingPolicy = auction.withPricingPolicy(updated); return new JOpenBidAuction<>(withUpdatedPricingPolicy); } public JOpenBidAuction withTickSize(Long updated) { - OpenBidAuction withUpdatedTickSize = auction.withTickSize(updated); + OpenBidSingleUnitAuction withUpdatedTickSize = auction.withTickSize(updated); return new JOpenBidAuction<>(withUpdatedTickSize); } @@ -98,7 +98,7 @@ public JOpenBidAuction withTickSize(Long updated) { * @return */ public static JOpenBidAuction withUniformClearingPolicy(PricingPolicy pricingPolicy, Long tickSize, T tradable) { - OpenBidAuction auction = OpenBidAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable); + OpenBidSingleUnitAuction auction = OpenBidSingleUnitAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable); return new JOpenBidAuction<>(auction); } @@ -109,7 +109,7 @@ public static JOpenBidAuction withUniformClearingPolicy( * @return */ public static JOpenBidAuction withUniformClearingPolicy(PricingPolicy pricingPolicy, T tradable) { - OpenBidAuction auction = OpenBidAuction.withUniformClearingPolicy(pricingPolicy, tradable); + OpenBidSingleUnitAuction auction = OpenBidSingleUnitAuction.withUniformClearingPolicy(pricingPolicy, tradable); return new JOpenBidAuction<>(auction); } @@ -121,7 +121,7 @@ public static JOpenBidAuction withUniformClearingPolicy( * @return */ public static JOpenBidAuction withDiscriminatoryClearingPolicy(PricingPolicy pricingPolicy, Long tickSize, T tradable) { - OpenBidAuction auction = OpenBidAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable); + OpenBidSingleUnitAuction auction = OpenBidSingleUnitAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable); return new JOpenBidAuction<>(auction); } @@ -132,7 +132,7 @@ public static JOpenBidAuction withDiscriminatoryClearing * @return */ public static JOpenBidAuction withDiscriminatoryClearingPolicy(PricingPolicy pricingPolicy, T tradable) { - OpenBidAuction auction = OpenBidAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tradable); + OpenBidSingleUnitAuction auction = OpenBidSingleUnitAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tradable); return new JOpenBidAuction<>(auction); } diff --git a/src/main/java/org/economicsl/auctions/singleunit/JSealedBidAuction.java b/src/main/java/org/economicsl/auctions/singleunit/JSealedBidAuction.java index 1a849dc..f9b46f5 100644 --- a/src/main/java/org/economicsl/auctions/singleunit/JSealedBidAuction.java +++ b/src/main/java/org/economicsl/auctions/singleunit/JSealedBidAuction.java @@ -17,8 +17,8 @@ import org.economicsl.auctions.SpotContract; -import org.economicsl.auctions.OrderTracker.*; -import org.economicsl.auctions.singleunit.orders.Order; +import org.economicsl.auctions.participants.OrderTracker.*; +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder; import org.economicsl.auctions.singleunit.pricing.PricingPolicy; import org.economicsl.core.Tradable; import scala.Option; @@ -35,9 +35,9 @@ */ class JSealedBidAuction extends JAuction> { - private SealedBidAuction auction; + private SealedBidSingleUnitAuction auction; - private JSealedBidAuction(SealedBidAuction auction) { + private JSealedBidAuction(SealedBidSingleUnitAuction auction) { this.auction = auction; } @@ -48,7 +48,7 @@ private JSealedBidAuction(SealedBidAuction auction) { * @return */ public CancelResult> cancel(UUID reference) { - Tuple2, Option> result = auction.cancel(reference); + Tuple2, Option> result = auction.cancel(reference); JSealedBidAuction jAuction = new JSealedBidAuction<>(result._1); return new CancelResult<>(jAuction, result._2); } @@ -58,7 +58,7 @@ public CancelResult> cancel(UUID reference) { * @return an instance of `ClearResult` class. */ public ClearResult> clear() { - Tuple2, Option>> result = auction.clear(); + Tuple2, Option>> result = auction.clear(); JSealedBidAuction jAuction = new JSealedBidAuction<>(result._1); return new ClearResult<>(jAuction, result._2); } @@ -68,19 +68,19 @@ public ClearResult> clear() { * @param order * @return */ - public InsertResult> insert(Tuple2> order) { - Tuple2, Either> result = auction.insert(order); + public InsertResult> insert(Tuple2> order) { + Tuple2, Either> result = auction.insert(order); JSealedBidAuction jAuction = new JSealedBidAuction<>(result._1()); return new InsertResult<>(jAuction, result._2()); } public JSealedBidAuction withPricingPolicy(PricingPolicy updated) { - SealedBidAuction withUpdatedPricingPolicy = auction.withPricingPolicy(updated); + SealedBidSingleUnitAuction withUpdatedPricingPolicy = auction.withPricingPolicy(updated); return new JSealedBidAuction<>(withUpdatedPricingPolicy); } public JSealedBidAuction withTickSize(Long updated) { - SealedBidAuction withUpdatedTickSize = auction.withTickSize(updated); + SealedBidSingleUnitAuction withUpdatedTickSize = auction.withTickSize(updated); return new JSealedBidAuction<>(withUpdatedTickSize); } @@ -92,7 +92,7 @@ public JSealedBidAuction withTickSize(Long updated) { * @return */ public static JSealedBidAuction withUniformClearingPolicy(PricingPolicy pricingPolicy, Long tickSize, T tradable) { - SealedBidAuction auction = SealedBidAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable); + SealedBidSingleUnitAuction auction = SealedBidSingleUnitAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable); return new JSealedBidAuction<>(auction); } @@ -103,7 +103,7 @@ public static JSealedBidAuction withUniformClearingPolic * @return */ public static JSealedBidAuction withUniformClearingPolicy(PricingPolicy pricingPolicy, T tradable) { - SealedBidAuction auction = SealedBidAuction.withUniformClearingPolicy(pricingPolicy, tradable); + SealedBidSingleUnitAuction auction = SealedBidSingleUnitAuction.withUniformClearingPolicy(pricingPolicy, tradable); return new JSealedBidAuction<>(auction); } @@ -115,7 +115,7 @@ public static JSealedBidAuction withUniformClearingPolic * @return */ public static JSealedBidAuction withDiscriminatoryClearingPolicy(PricingPolicy pricingPolicy, Long tickSize, T tradable) { - SealedBidAuction auction = SealedBidAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable); + SealedBidSingleUnitAuction auction = SealedBidSingleUnitAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable); return new JSealedBidAuction<>(auction); } @@ -126,7 +126,7 @@ public static JSealedBidAuction withDiscriminatoryCleari * @return */ public static JSealedBidAuction withDiscriminatoryClearingPolicy(PricingPolicy pricingPolicy, T tradable) { - SealedBidAuction auction = SealedBidAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tradable); + SealedBidSingleUnitAuction auction = SealedBidSingleUnitAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tradable); return new JSealedBidAuction<>(auction); } diff --git a/src/main/scala/org/economicsl/auctions/Auction.scala b/src/main/scala/org/economicsl/auctions/Auction.scala new file mode 100644 index 0000000..cd7ffa0 --- /dev/null +++ b/src/main/scala/org/economicsl/auctions/Auction.scala @@ -0,0 +1,61 @@ +/* +Copyright (c) 2017 KAPSARC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package org.economicsl.auctions + +import org.economicsl.auctions.participants.Token +import org.economicsl.core.util.Timestamper +import org.economicsl.core.{Currency, Tradable} + + +/** Base trait for all auction implementations. + * + * @tparam T + * @tparam A + * @note Note the use of F-bounded polymorphism over Type classes. We developed an alternative implementation using the + * Type class pattern that was quite elegant, however Type classes can not be used directly from Java. In order + * to use the Type class implementation from Java, we would need to develop (and maintain!) separate wrappers for + * each auction implementation. + */ +trait Auction[T <: Tradable, O <: Order[T], +A <: Auction[T, O, A]] + extends ReferenceGenerator + with Timestamper { + this: A => + + import org.economicsl.auctions.participants.OrderTracker._ + + def cancel(reference: Reference): (A, Option[Canceled]) + + def clear: (A, Option[Stream[SpotContract]]) + + def insert(kv: (Token, O)): (A, Either[Rejected, Accepted]) + + def tickSize: Currency + + def tradable: T + + /** Returns an auction of type `A` the encapsulates the current auction state but with a new tick size. */ + def withTickSize(updated: Currency): A + +} + + +object Auction { + + /** Need some data structure to convey the relevant information about an auction to participants. */ + final case class AuctionProtocol(tickSize: Currency, tradable: Tradable) + +} + diff --git a/src/main/scala/org/economicsl/auctions/Contract.scala b/src/main/scala/org/economicsl/auctions/Contract.scala index b1b3dad..101ed20 100644 --- a/src/main/scala/org/economicsl/auctions/Contract.scala +++ b/src/main/scala/org/economicsl/auctions/Contract.scala @@ -20,6 +20,7 @@ package org.economicsl.auctions * * @author davidrpugh * @since 0.1.0 + * @todo move this to the settlement repo when ready. */ trait Contract extends Serializable { diff --git a/src/main/scala/org/economicsl/auctions/Order.scala b/src/main/scala/org/economicsl/auctions/Order.scala new file mode 100644 index 0000000..40fde90 --- /dev/null +++ b/src/main/scala/org/economicsl/auctions/Order.scala @@ -0,0 +1,14 @@ +package org.economicsl.auctions + +import org.economicsl.core.Tradable + + +/** Base trait for all orders. + * + * @tparam T each `Order` must be issued for a particular type of `Tradable`. + * @author davidrpugh + * @since 0.2.0 + */ +trait Order[+T <: Tradable] extends Contract { + this: PriceQuantitySchedule[T] => +} diff --git a/src/main/scala/org/economicsl/auctions/PriceQuantitySchedule.scala b/src/main/scala/org/economicsl/auctions/PriceQuantitySchedule.scala index 45cbeee..56efab9 100644 --- a/src/main/scala/org/economicsl/auctions/PriceQuantitySchedule.scala +++ b/src/main/scala/org/economicsl/auctions/PriceQuantitySchedule.scala @@ -26,7 +26,6 @@ import scala.collection.GenIterable * @since 0.1.0 */ trait PriceQuantitySchedule[+T <: Tradable] { - this: Contract => type PricePoint = (Price, Quantity) diff --git a/src/main/scala/org/economicsl/auctions/AuctionParticipant.scala b/src/main/scala/org/economicsl/auctions/QuotingPolicy.scala similarity index 68% rename from src/main/scala/org/economicsl/auctions/AuctionParticipant.scala rename to src/main/scala/org/economicsl/auctions/QuotingPolicy.scala index cd82991..af6ff92 100644 --- a/src/main/scala/org/economicsl/auctions/AuctionParticipant.scala +++ b/src/main/scala/org/economicsl/auctions/QuotingPolicy.scala @@ -15,9 +15,13 @@ limitations under the License. */ package org.economicsl.auctions +import org.economicsl.auctions.quotes.{Quote, QuoteRequest} +import org.economicsl.core.Tradable + + +/** Mixin trait that provides an `Auction` with the ability to process `QuoteRequest`. */ +trait QuotingPolicy[T <: Tradable] { + + def receive(request: QuoteRequest[T]): Quote -trait AuctionParticipant[A <: AuctionParticipant[A]] - extends OrderIssuer[A] - with OrderTracker[A] { - this: A => } diff --git a/src/main/scala/org/economicsl/auctions/SinglePricePoint.scala b/src/main/scala/org/economicsl/auctions/SinglePricePoint.scala index cb55aea..e736330 100644 --- a/src/main/scala/org/economicsl/auctions/SinglePricePoint.scala +++ b/src/main/scala/org/economicsl/auctions/SinglePricePoint.scala @@ -26,7 +26,6 @@ import scala.collection.immutable * @since 0.1.0 */ trait SinglePricePoint[+T <: Tradable] extends PriceQuantitySchedule[T] { - this: Contract => /** Limit price (per unit of the `Tradable`) for the Order. * diff --git a/src/main/scala/org/economicsl/auctions/SingleUnit.scala b/src/main/scala/org/economicsl/auctions/SingleUnit.scala index 0c17ceb..4f421ee 100644 --- a/src/main/scala/org/economicsl/auctions/SingleUnit.scala +++ b/src/main/scala/org/economicsl/auctions/SingleUnit.scala @@ -24,7 +24,6 @@ import org.economicsl.core.{Quantity, Tradable} * @since 0.1.0 */ trait SingleUnit[+T <: Tradable] extends SinglePricePoint[T] { - this: Contract => val quantity: Quantity = Quantity.single diff --git a/src/main/scala/org/economicsl/auctions/actors/AuctionActor.scala b/src/main/scala/org/economicsl/auctions/actors/AuctionActor.scala index 532e4dd..469d3d5 100644 --- a/src/main/scala/org/economicsl/auctions/actors/AuctionActor.scala +++ b/src/main/scala/org/economicsl/auctions/actors/AuctionActor.scala @@ -2,19 +2,16 @@ package org.economicsl.auctions.actors import akka.actor.{ActorRef, Terminated} import akka.routing.{ActorRefRoutee, BroadcastRoutingLogic, Router} -import org.economicsl.auctions.{Reference, Token} -import org.economicsl.auctions.singleunit.Auction -import org.economicsl.auctions.singleunit.orders.Order +import org.economicsl.auctions._ +import org.economicsl.auctions.participants.Token import org.economicsl.core.Tradable - - -trait AuctionActor[T <: Tradable, A <: Auction[T, A]] +trait AuctionActor[T <: Tradable, O <: Order[T], A <: Auction[T, O, A]] extends StackableActor { import AuctionActor._ - import AuctionParticipantActor._ + import Auction._ var auction: A @@ -30,16 +27,6 @@ trait AuctionActor[T <: Tradable, A <: Auction[T, A]] } protected def processOrders: Receive = { - case message @ InsertOrder(token, order: Order[T]) => - val (updatedAuction, response) = auction.insert(token -> order) - response match { - case Right(accepted) => - sender() ! accepted - auction = updatedAuction - case Left(rejected) => - sender() ! rejected - } - super.receive(message) case CancelOrder(reference) => val (updatedAuction, cancelResult) = auction.cancel(reference) cancelResult match { @@ -88,7 +75,7 @@ object AuctionActor { final case class CancelOrder(reference: Reference) - final case class InsertOrder[T <: Tradable](token: Token, order: Order[T]) + final case class InsertOrder[+T <: Tradable](token: Token, order: Order[T]) final case class DeregisterAuctionParticipant(participant: ActorRef) diff --git a/src/main/scala/org/economicsl/auctions/actors/AuctionParticipantActor.scala b/src/main/scala/org/economicsl/auctions/actors/AuctionParticipantActor.scala index 7b122e2..4dd065b 100644 --- a/src/main/scala/org/economicsl/auctions/actors/AuctionParticipantActor.scala +++ b/src/main/scala/org/economicsl/auctions/actors/AuctionParticipantActor.scala @@ -17,42 +17,34 @@ package org.economicsl.auctions.actors import akka.actor.ActorRef -import org.economicsl.auctions.AuctionParticipant -import org.economicsl.core.{Currency, Tradable} +import org.economicsl.auctions.Auction +import org.economicsl.auctions.participants.AuctionParticipant +import org.economicsl.core.Tradable /** Base trait for all `AuctionParticipant` actors. * * @author davidrpugh * @since 0.2.0 - * @todo if auction registry fails for some reason while the auction participant is "active", the auction registry will - * need to be re-identified; during re-identification auction participant should continue to process messages - * received by any auctions to which it has previously registered. */ trait AuctionParticipantActor[A <: AuctionParticipant[A]] extends OrderTrackingActor[A] with OrderIssuingActor[A] { - import AuctionParticipantActor._ + import Auction._ override def receive: Receive = { case protocol : AuctionProtocol => - auctions = auctions + (sender() -> protocol) + auctionParticipant = auctionParticipant + protocol + auctions = auctions + (protocol.tradable -> sender()) + super.receive(protocol) case message => super.receive(message) } - /* An `AuctionParticipant` needs to keep track of multiple auction protocols. */ - protected var auctions: Map[ActorRef, AuctionProtocol] + /* An `AuctionParticipant` needs to keep track of multiple `ActorRef` instances. */ + protected var auctions: Map[Tradable, ActorRef] protected var auctionParticipant: A -} - - -object AuctionParticipantActor { - - /** Need some data structure to convey the information about an auction to participants. */ - final case class AuctionProtocol(tickSize: Currency, tradable: Tradable) - } \ No newline at end of file diff --git a/src/main/scala/org/economicsl/auctions/actors/ClearingSchedule.scala b/src/main/scala/org/economicsl/auctions/actors/ClearingSchedule.scala index ea30076..00b5501 100644 --- a/src/main/scala/org/economicsl/auctions/actors/ClearingSchedule.scala +++ b/src/main/scala/org/economicsl/auctions/actors/ClearingSchedule.scala @@ -16,8 +16,7 @@ limitations under the License. package org.economicsl.auctions.actors import akka.actor.ReceiveTimeout -import org.economicsl.auctions.singleunit.Auction -import org.economicsl.auctions.singleunit.orders.Order +import org.economicsl.auctions.{Auction, Order} import org.economicsl.core.Tradable import scala.concurrent.ExecutionContext @@ -25,9 +24,9 @@ import scala.concurrent.duration.FiniteDuration /** Mixin trait that specifies a schedule for auction clearing events. */ -sealed trait ClearingSchedule[T <: Tradable, A <: Auction[T, A]] +sealed trait ClearingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A]] extends StackableActor { - this: AuctionActor[T, A] => + this: AuctionActor[T, O, A] => } @@ -40,14 +39,14 @@ object ClearingSchedule { /** Schedules a clearing event to occur whenever a new order is inserted into the auction. */ -trait BidderActivityClearingSchedule[T <: Tradable, A <: Auction[T, A]] - extends ClearingSchedule[T, A] { - this: AuctionActor[T, A] => +trait BidderActivityClearingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A]] + extends ClearingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => import AuctionActor._ override def receive: Receive = { - case message @ InsertOrder(_, _: Order[T]) => + case message @ InsertOrder(_, _: O) => settlementService match { case Some(actorRef) => val (clearedAuction, contracts) = auction.clear @@ -67,9 +66,9 @@ trait BidderActivityClearingSchedule[T <: Tradable, A <: Auction[T, A]] /** Schedules a clearing event to occur whenever no new orders have been received for a specified period. */ -trait BidderInActivityClearingSchedule[T <: Tradable, A <: Auction[T, A]] - extends ClearingSchedule[T, A] { - this: AuctionActor[T, A] => +trait BidderInActivityClearingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A]] + extends ClearingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => def timeout: FiniteDuration @@ -80,7 +79,7 @@ trait BidderInActivityClearingSchedule[T <: Tradable, A <: Auction[T, A]] } override def receive: Receive = { - case message @ ReceiveTimeout => + case ReceiveTimeout => settlementService match { case Some(actorRef) => val (clearedAuction, contracts) = auction.clear @@ -91,7 +90,7 @@ trait BidderInActivityClearingSchedule[T <: Tradable, A <: Auction[T, A]] // Can only occur in remote context where AuctionActor might need to be created without knowledge of the // location of the SettlementActor (and hence without knowledge of the ActorRef). } - super.receive(message) + super.receive(ReceiveTimeout) case message => super.receive(message) } @@ -100,9 +99,9 @@ trait BidderInActivityClearingSchedule[T <: Tradable, A <: Auction[T, A]] /** Schedules a clearing event to occur after fixed time intervals. */ -trait PeriodicClearingSchedule[T <: Tradable, A <: Auction[T, A]] - extends ClearingSchedule[T, A] { - this: AuctionActor[T, A] => +trait PeriodicClearingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A]] + extends ClearingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => import ClearingSchedule._ import context.dispatcher // implicitly passed to the scheduleClear method! @@ -118,7 +117,7 @@ trait PeriodicClearingSchedule[T <: Tradable, A <: Auction[T, A]] } override def receive: Receive = { - case message @ ClearRequest => + case ClearRequest => settlementService match { case Some(actorRef) => val (updatedAuction, contracts) = auction.clear @@ -130,7 +129,7 @@ trait PeriodicClearingSchedule[T <: Tradable, A <: Auction[T, A]] // Can only occur in remote context where AuctionActor might need to be created without knowledge of the // location of the SettlementActor (and hence without knowledge of the ActorRef). } - super.receive(message) + super.receive(ClearRequest) case message => super.receive(message) } @@ -142,8 +141,35 @@ trait PeriodicClearingSchedule[T <: Tradable, A <: Auction[T, A]] } +/** Schedules a clearing event in response to a specific request. */ +trait OnDemandClearingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A]] + extends ClearingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => + + import ClearingSchedule._ + + override def receive: Receive = { + case ClearRequest => + settlementService match { + case Some(actorRef) => + val (updatedAuction, contracts) = auction.clear + contracts.foreach(contract => actorRef ! contract) // eager eval of stream! + auction = updatedAuction + case None => + ??? // todo how to handle this case? + // Can only occur in remote context where AuctionActor might need to be created without knowledge of the + // location of the SettlementActor (and hence without knowledge of the ActorRef). + } + super.receive(ClearRequest) + case message => + super.receive(message) + } + +} + + /** Schedules a clearing event to occur after random time intervals. */ -trait RandomClearingSchedule[T <: Tradable, A <: Auction[T, A]] - extends PeriodicClearingSchedule[T, A] { - this: AuctionActor[T, A] => +trait RandomClearingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A]] + extends PeriodicClearingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => } diff --git a/src/main/scala/org/economicsl/auctions/actors/ContinuousAuctionActor.scala b/src/main/scala/org/economicsl/auctions/actors/ContinuousSingleUnitAuctionActor.scala similarity index 60% rename from src/main/scala/org/economicsl/auctions/actors/ContinuousAuctionActor.scala rename to src/main/scala/org/economicsl/auctions/actors/ContinuousSingleUnitAuctionActor.scala index aae060b..2c6d8ea 100644 --- a/src/main/scala/org/economicsl/auctions/actors/ContinuousAuctionActor.scala +++ b/src/main/scala/org/economicsl/auctions/actors/ContinuousSingleUnitAuctionActor.scala @@ -16,17 +16,18 @@ limitations under the License. package org.economicsl.auctions.actors import akka.actor.{ActorRef, Props} -import org.economicsl.auctions.singleunit.{Auction, SealedBidAuction} +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder +import org.economicsl.auctions.singleunit.{SealedBidSingleUnitAuction, SingleUnitAuction} import org.economicsl.auctions.singleunit.pricing.PricingPolicy import org.economicsl.core.{Currency, Tradable} -trait ContinuousAuctionActor[T <: Tradable, A <: Auction[T, A]] - extends AuctionActor[T, A] - with BidderActivityClearingSchedule[T, A] +trait ContinuousSingleUnitAuctionActor[T <: Tradable, A <: SingleUnitAuction[T, A]] + extends SingleUnitAuctionActor[T, A] + with BidderActivityClearingSchedule[T, SingleUnitOrder[T], A] -object ContinuousAuctionActor { +object ContinuousSingleUnitAuctionActor { def withDiscriminatoryClearingPolicy[T <: Tradable] (pricingPolicy: PricingPolicy[T], @@ -34,8 +35,8 @@ object ContinuousAuctionActor { tickSize: Currency, tradable: T) : Props = { - val auction = SealedBidAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable) - Props(new ContinuousAuctionActorImpl(auction, Some(settlementService))) + val auction = SealedBidSingleUnitAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable) + Props(new ContinuousSingleUnitAuctionActorImpl(auction, Some(settlementService))) } def withUniformClearingPolicy[T <: Tradable] @@ -44,14 +45,14 @@ object ContinuousAuctionActor { tickSize: Currency, tradable: T) : Props = { - val auction = SealedBidAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable) - Props(new ContinuousAuctionActorImpl(auction, Some(settlementService))) + val auction = SealedBidSingleUnitAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable) + Props(new ContinuousSingleUnitAuctionActorImpl(auction, Some(settlementService))) } - private class ContinuousAuctionActorImpl[T <: Tradable]( - var auction: SealedBidAuction[T], + private class ContinuousSingleUnitAuctionActorImpl[T <: Tradable]( + var auction: SealedBidSingleUnitAuction[T], val settlementService: Option[ActorRef]) - extends ContinuousAuctionActor[T, SealedBidAuction[T]] + extends ContinuousSingleUnitAuctionActor[T, SealedBidSingleUnitAuction[T]] } diff --git a/src/main/scala/org/economicsl/auctions/actors/OrderIssuingActor.scala b/src/main/scala/org/economicsl/auctions/actors/OrderIssuingActor.scala index 2353f56..02e6bab 100644 --- a/src/main/scala/org/economicsl/auctions/actors/OrderIssuingActor.scala +++ b/src/main/scala/org/economicsl/auctions/actors/OrderIssuingActor.scala @@ -1,6 +1,21 @@ +/* +Copyright 2016 David R. Pugh + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package org.economicsl.auctions.actors -import org.economicsl.auctions.AuctionParticipant +import org.economicsl.auctions.participants.AuctionParticipant trait OrderIssuingActor[A <: AuctionParticipant[A]] diff --git a/src/main/scala/org/economicsl/auctions/actors/OrderTrackingActor.scala b/src/main/scala/org/economicsl/auctions/actors/OrderTrackingActor.scala index 579bfa4..43f6d0e 100644 --- a/src/main/scala/org/economicsl/auctions/actors/OrderTrackingActor.scala +++ b/src/main/scala/org/economicsl/auctions/actors/OrderTrackingActor.scala @@ -15,7 +15,7 @@ limitations under the License. */ package org.economicsl.auctions.actors -import org.economicsl.auctions.AuctionParticipant +import org.economicsl.auctions.participants.AuctionParticipant /** Mixin trait providing `OrderTracking` behavior. @@ -27,7 +27,7 @@ trait OrderTrackingActor[A <: AuctionParticipant[A]] extends StackableActor { this: AuctionParticipantActor[A] => - import org.economicsl.auctions.OrderTracker._ + import org.economicsl.auctions.participants.OrderTracker._ /** Forward received messages to `AuctionParticipant` for processing. * diff --git a/src/main/scala/org/economicsl/auctions/actors/PeriodicAuctionActor.scala b/src/main/scala/org/economicsl/auctions/actors/PeriodicSingleUnitAuctionActor.scala similarity index 64% rename from src/main/scala/org/economicsl/auctions/actors/PeriodicAuctionActor.scala rename to src/main/scala/org/economicsl/auctions/actors/PeriodicSingleUnitAuctionActor.scala index 45d1148..9636bb5 100644 --- a/src/main/scala/org/economicsl/auctions/actors/PeriodicAuctionActor.scala +++ b/src/main/scala/org/economicsl/auctions/actors/PeriodicSingleUnitAuctionActor.scala @@ -16,19 +16,20 @@ limitations under the License. package org.economicsl.auctions.actors import akka.actor.{ActorRef, Props} -import org.economicsl.auctions.singleunit.{Auction, SealedBidAuction} +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder +import org.economicsl.auctions.singleunit.{SealedBidSingleUnitAuction, SingleUnitAuction} import org.economicsl.auctions.singleunit.pricing.PricingPolicy import org.economicsl.core.{Currency, Tradable} import scala.concurrent.duration.FiniteDuration -trait PeriodicAuctionActor[T <: Tradable, A <: Auction[T, A]] - extends AuctionActor[T, A] - with PeriodicClearingSchedule[T, A] +trait PeriodicSingleUnitAuctionActor[T <: Tradable, A <: SingleUnitAuction[T, A]] + extends SingleUnitAuctionActor[T, A] + with PeriodicClearingSchedule[T, SingleUnitOrder[T], A] -object PeriodicAuctionActor { +object PeriodicSingleUnitAuctionActor { def withDiscriminatoryClearingPolicy[T <: Tradable] (initialDelay: FiniteDuration, @@ -38,8 +39,8 @@ object PeriodicAuctionActor { tickSize: Currency, tradable: T) : Props = { - val auction = SealedBidAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable) - Props(new PeriodicAuctionActorImpl(auction, initialDelay, interval, Some(settlementService))) + val auction = SealedBidSingleUnitAuction.withDiscriminatoryClearingPolicy(pricingPolicy, tickSize, tradable) + Props(new PeriodicSingleUnitAuctionActorImpl(auction, initialDelay, interval, Some(settlementService))) } def withUniformClearingPolicy[T <: Tradable] @@ -50,18 +51,16 @@ object PeriodicAuctionActor { tickSize: Currency, tradable: T) : Props = { - val auction = SealedBidAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable) - Props(new PeriodicAuctionActorImpl(auction, initialDelay, interval, Some(settlementService))) + val auction = SealedBidSingleUnitAuction.withUniformClearingPolicy(pricingPolicy, tickSize, tradable) + Props(new PeriodicSingleUnitAuctionActorImpl(auction, initialDelay, interval, Some(settlementService))) } - private class PeriodicAuctionActorImpl[T <: Tradable]( - var auction: SealedBidAuction[T], + private class PeriodicSingleUnitAuctionActorImpl[T <: Tradable]( + var auction: SealedBidSingleUnitAuction[T], val initialDelay: FiniteDuration, val interval: FiniteDuration, val settlementService: Option[ActorRef]) - extends PeriodicAuctionActor[T, SealedBidAuction[T]] { - - } + extends PeriodicSingleUnitAuctionActor[T, SealedBidSingleUnitAuction[T]] } diff --git a/src/main/scala/org/economicsl/auctions/actors/QuotingSchedule.scala b/src/main/scala/org/economicsl/auctions/actors/QuotingSchedule.scala index 69dbd1a..b97fd1e 100644 --- a/src/main/scala/org/economicsl/auctions/actors/QuotingSchedule.scala +++ b/src/main/scala/org/economicsl/auctions/actors/QuotingSchedule.scala @@ -16,9 +16,8 @@ limitations under the License. package org.economicsl.auctions.actors import akka.actor.ReceiveTimeout +import org.economicsl.auctions.{Auction, Order, QuotingPolicy} import org.economicsl.auctions.quotes.QuoteRequest -import org.economicsl.auctions.singleunit.OpenBidAuction -import org.economicsl.auctions.singleunit.orders.Order import org.economicsl.core.Tradable import scala.concurrent.ExecutionContext @@ -26,16 +25,16 @@ import scala.concurrent.duration.FiniteDuration /** Mixin trait that specifies a schedule for auction quoting events. */ -sealed trait QuotingSchedule[T <: Tradable] +sealed trait QuotingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A] with QuotingPolicy[T]] extends StackableActor { - this: AuctionActor[T, OpenBidAuction[T]] => + this: AuctionActor[T, O, A] => } /** Schedules a quoting event to occur whenever a new order is inserted into the auction. */ -trait BidderActivityQuotingSchedule[T <: Tradable] - extends QuotingSchedule[T] { - this: AuctionActor[T, OpenBidAuction[T]] => +trait BidderActivityQuotingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A] with QuotingPolicy[T]] + extends QuotingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => import AuctionActor._ @@ -51,9 +50,9 @@ trait BidderActivityQuotingSchedule[T <: Tradable] /** Schedules a quoting event to occur whenever no new orders have been received for a specified period. */ -trait BidderInActivityQuotingSchedule[T <: Tradable] - extends QuotingSchedule[T] { - this: AuctionActor[T, OpenBidAuction[T]] => +trait BidderInActivityQuotingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A] with QuotingPolicy[T]] + extends QuotingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => def timeout: FiniteDuration @@ -74,9 +73,9 @@ trait BidderInActivityQuotingSchedule[T <: Tradable] /** Schedules a quoting event in response to an `AuctionParticipantActor` request. */ -trait OnDemandQuotingSchedule[T <: Tradable] - extends QuotingSchedule[T] { - this: AuctionActor[T, OpenBidAuction[T]] => +trait OnDemandQuotingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A] with QuotingPolicy[T]] + extends QuotingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => override def receive: Receive = { case request: QuoteRequest[T] => @@ -91,9 +90,9 @@ trait OnDemandQuotingSchedule[T <: Tradable] /** Schedules a clearing event to occur after fixed time intervals. */ -trait PeriodicQuotingSchedule[T <: Tradable] - extends QuotingSchedule[T] { - this: AuctionActor[T, OpenBidAuction[T]] => +trait PeriodicQuotingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A] with QuotingPolicy[T]] + extends QuotingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => import context.dispatcher // implicitly passed to the scheduleQuoteRequest method! @@ -120,7 +119,7 @@ trait PeriodicQuotingSchedule[T <: Tradable] /** Schedules a quoting event to occur after random time intervals. */ -trait RandomQuotingSchedule[T <: Tradable] - extends PeriodicQuotingSchedule[T] { - this: AuctionActor[T, OpenBidAuction[T]] => +trait RandomQuotingSchedule[T <: Tradable, O <: Order[T], A <: Auction[T, O, A] with QuotingPolicy[T]] + extends PeriodicQuotingSchedule[T, O, A] { + this: AuctionActor[T, O, A] => } diff --git a/src/main/scala/org/economicsl/auctions/actors/SingleUnitAuctionActor.scala b/src/main/scala/org/economicsl/auctions/actors/SingleUnitAuctionActor.scala new file mode 100644 index 0000000..baf0cd3 --- /dev/null +++ b/src/main/scala/org/economicsl/auctions/actors/SingleUnitAuctionActor.scala @@ -0,0 +1,25 @@ +package org.economicsl.auctions.actors + +import org.economicsl.auctions.actors.AuctionActor.InsertOrder +import org.economicsl.auctions.singleunit.SingleUnitAuction +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder +import org.economicsl.core.Tradable + + +trait SingleUnitAuctionActor[T <: Tradable, A <: SingleUnitAuction[T, A]] + extends AuctionActor[T, SingleUnitOrder[T], A] { + + override def receive: Receive = { + case message @ InsertOrder(token, order: SingleUnitOrder[T]) => + val (updatedAuction, response) = auction.insert(token -> order) + response match { + case Right(accepted) => + sender() ! accepted + auction = updatedAuction + case Left(rejected) => + sender() ! rejected + } + super.receive(message) + } + +} diff --git a/src/main/scala/org/economicsl/auctions/multiunit/LimitAskOrder.scala b/src/main/scala/org/economicsl/auctions/multiunit/LimitAskOrder.scala index ba04ea4..eb836cf 100644 --- a/src/main/scala/org/economicsl/auctions/multiunit/LimitAskOrder.scala +++ b/src/main/scala/org/economicsl/auctions/multiunit/LimitAskOrder.scala @@ -32,7 +32,7 @@ import org.economicsl.core.{Price, Quantity, Tradable} * @since 0.1.0 */ class LimitAskOrder[+T <: Tradable](val issuer: UUID, val limit: Price, val quantity: Quantity, val tradable: T) - extends AskOrder[T] with SinglePricePoint[T] + extends SinglePricePointAskOrder[T] with SinglePricePoint[T] /** Companion object for `LimitAskOrder`. diff --git a/src/main/scala/org/economicsl/auctions/multiunit/LimitBidOrder.scala b/src/main/scala/org/economicsl/auctions/multiunit/LimitBidOrder.scala index f702b94..c65d623 100644 --- a/src/main/scala/org/economicsl/auctions/multiunit/LimitBidOrder.scala +++ b/src/main/scala/org/economicsl/auctions/multiunit/LimitBidOrder.scala @@ -32,7 +32,7 @@ import org.economicsl.core.{Price, Quantity, Tradable} * @since 0.1.0 */ class LimitBidOrder[+T <: Tradable](val issuer: UUID, val limit: Price, val quantity: Quantity, val tradable: T) - extends BidOrder[T] with SinglePricePoint[T] + extends SinglePricePointBidOrder[T] with SinglePricePoint[T] /** Companion object for `LimitBidOrder`. diff --git a/src/main/scala/org/economicsl/auctions/multiunit/MarketAskOrder.scala b/src/main/scala/org/economicsl/auctions/multiunit/MarketAskOrder.scala index 4341e7c..40ab919 100644 --- a/src/main/scala/org/economicsl/auctions/multiunit/MarketAskOrder.scala +++ b/src/main/scala/org/economicsl/auctions/multiunit/MarketAskOrder.scala @@ -31,7 +31,7 @@ import org.economicsl.core.{Price, Quantity, Tradable} * @since 0.1.0 */ class MarketAskOrder[+T <: Tradable](val issuer: UUID, val quantity: Quantity, val tradable: T) - extends AskOrder[T] with SinglePricePoint[T] { + extends SinglePricePointAskOrder[T] with SinglePricePoint[T] { val limit: Price = Price.MinValue diff --git a/src/main/scala/org/economicsl/auctions/multiunit/MarketBidOrder.scala b/src/main/scala/org/economicsl/auctions/multiunit/MarketBidOrder.scala index 258aeaf..0f8493c 100644 --- a/src/main/scala/org/economicsl/auctions/multiunit/MarketBidOrder.scala +++ b/src/main/scala/org/economicsl/auctions/multiunit/MarketBidOrder.scala @@ -31,7 +31,7 @@ import org.economicsl.core.{Price, Quantity, Tradable} * @since 0.1.0 */ class MarketBidOrder[+T <: Tradable](val issuer: UUID, val quantity: Quantity, val tradable: T) - extends BidOrder[T] with SinglePricePoint[T] { + extends SinglePricePointBidOrder[T] with SinglePricePoint[T] { val limit: Price = Price.MaxValue diff --git a/src/main/scala/org/economicsl/auctions/multiunit/SinglePricePointAuction.scala b/src/main/scala/org/economicsl/auctions/multiunit/SinglePricePointAuction.scala new file mode 100644 index 0000000..6e1e7bb --- /dev/null +++ b/src/main/scala/org/economicsl/auctions/multiunit/SinglePricePointAuction.scala @@ -0,0 +1,10 @@ +package org.economicsl.auctions.multiunit + +import org.economicsl.auctions.Auction +import org.economicsl.core.Tradable + + +trait SinglePricePointAuction[T <: Tradable, +A <: SinglePricePointAuction[T, A]] + extends Auction[T, SinglePricePointOrder[T], A] { + this: A => +} diff --git a/src/main/scala/org/economicsl/auctions/multiunit/Order.scala b/src/main/scala/org/economicsl/auctions/multiunit/SinglePricePointOrder.scala similarity index 79% rename from src/main/scala/org/economicsl/auctions/multiunit/Order.scala rename to src/main/scala/org/economicsl/auctions/multiunit/SinglePricePointOrder.scala index a031a32..2728c3e 100644 --- a/src/main/scala/org/economicsl/auctions/multiunit/Order.scala +++ b/src/main/scala/org/economicsl/auctions/multiunit/SinglePricePointOrder.scala @@ -15,7 +15,7 @@ limitations under the License. */ package org.economicsl.auctions.multiunit -import org.economicsl.auctions.Contract +import org.economicsl.auctions.{Order, SinglePricePoint} import org.economicsl.core.Tradable @@ -25,7 +25,7 @@ import org.economicsl.core.Tradable * @author davidrpugh * @since 0.1.0 */ -sealed trait Order[+T <: Tradable] extends Contract +sealed trait SinglePricePointOrder[+T <: Tradable] extends Order[T] with SinglePricePoint[T] /** Base trait for all multi-unit orders to sell a particular `Tradable`. @@ -34,7 +34,7 @@ sealed trait Order[+T <: Tradable] extends Contract * @author davidrpugh * @since 0.1.0 */ -trait AskOrder[+T <: Tradable] extends Order[T] +trait SinglePricePointAskOrder[+T <: Tradable] extends SinglePricePointOrder[T] /** Base trait for all multi-unit orders to buy a particular `Tradable` @@ -43,4 +43,4 @@ trait AskOrder[+T <: Tradable] extends Order[T] * @author davidrpugh * @since 0.1.0 */ -trait BidOrder[+T <: Tradable] extends Order[T] \ No newline at end of file +trait SinglePricePointBidOrder[+T <: Tradable] extends SinglePricePointOrder[T] \ No newline at end of file diff --git a/src/main/scala/org/economicsl/auctions/package.scala b/src/main/scala/org/economicsl/auctions/package.scala index 0962c01..93a592d 100644 --- a/src/main/scala/org/economicsl/auctions/package.scala +++ b/src/main/scala/org/economicsl/auctions/package.scala @@ -31,7 +31,4 @@ package object auctions { /* Type alias used to denote a unique (to the auction!) identifier for an accepted order. */ type Reference = UUID - /* Type alias used to denote a unique (to the auction participant!) identifier for an accepted order. */ - type Token = UUID - } diff --git a/src/main/scala/org/economicsl/auctions/participants/AuctionParticipant.scala b/src/main/scala/org/economicsl/auctions/participants/AuctionParticipant.scala new file mode 100644 index 0000000..9cba466 --- /dev/null +++ b/src/main/scala/org/economicsl/auctions/participants/AuctionParticipant.scala @@ -0,0 +1,45 @@ +/* +Copyright (c) 2017 KAPSARC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package org.economicsl.auctions.participants + +import org.economicsl.auctions.Auction +import org.economicsl.core.Tradable + + +trait AuctionParticipant[A <: AuctionParticipant[A]] + extends OrderIssuer[A] + with OrderTracker[A] { + this: A => + + import Auction._ + + def + (protocol: AuctionProtocol): A = { + val updatedAuctions = auctions + (protocol.tradable -> protocol) + withAuctions(updatedAuctions) + } + + def - (tradable: Tradable): A = { + val updatedAuctions = auctions - tradable + withAuctions(updatedAuctions) + } + + protected def withAuctions(updated: Map[Tradable, AuctionProtocol]): A + + /** Each `AuctionParticipant` should maintain a collection of auctions in which it actively participates. */ + protected def auctions: Map[Tradable, AuctionProtocol] + +} + diff --git a/src/main/scala/org/economicsl/auctions/OrderIssuer.scala b/src/main/scala/org/economicsl/auctions/participants/OrderIssuer.scala similarity index 88% rename from src/main/scala/org/economicsl/auctions/OrderIssuer.scala rename to src/main/scala/org/economicsl/auctions/participants/OrderIssuer.scala index 4fa53c7..d7fdaf8 100644 --- a/src/main/scala/org/economicsl/auctions/OrderIssuer.scala +++ b/src/main/scala/org/economicsl/auctions/participants/OrderIssuer.scala @@ -13,8 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package org.economicsl.auctions +package org.economicsl.auctions.participants +import org.economicsl.auctions.Issuer trait OrderIssuer[A <: OrderIssuer[A]] extends TokenGenerator { diff --git a/src/main/scala/org/economicsl/auctions/OrderTracker.scala b/src/main/scala/org/economicsl/auctions/participants/OrderTracker.scala similarity index 93% rename from src/main/scala/org/economicsl/auctions/OrderTracker.scala rename to src/main/scala/org/economicsl/auctions/participants/OrderTracker.scala index 8710d1e..6beff39 100644 --- a/src/main/scala/org/economicsl/auctions/OrderTracker.scala +++ b/src/main/scala/org/economicsl/auctions/participants/OrderTracker.scala @@ -13,8 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package org.economicsl.auctions +package org.economicsl.auctions.participants +import org.economicsl.auctions.{Contract, Reference, SinglePricePoint} import org.economicsl.core.Tradable import org.economicsl.core.util.Timestamp @@ -25,11 +26,18 @@ trait OrderTracker[A <: OrderTracker[A]] { import OrderTracker._ - final def trackOrders(accepted: Accepted): A = { + val outstandingOrders: Map[Token, (Reference, Contract)] + + def trackOrders(accepted: Accepted): A = { val updated = outstandingOrders + accepted.kv withOutstandingOrders(updated) } + def trackOrders(canceled: Canceled): A = { + val updated = outstandingOrders - canceled.token + withOutstandingOrders(updated) + } + /** * * @param rejected @@ -40,16 +48,9 @@ trait OrderTracker[A <: OrderTracker[A]] { this // todo is this the most appropriate default behavior? } - final def trackOrders(canceled: Canceled): A = { - val updated = outstandingOrders - canceled.token - withOutstandingOrders(updated) - } - /** Factory method used by sub-classes to create an `A`. */ protected def withOutstandingOrders(updated: Map[Token, (Reference, Contract)]): A - protected val outstandingOrders: Map[Token, (Reference, Contract)] - } diff --git a/src/main/scala/org/economicsl/auctions/TokenGenerator.scala b/src/main/scala/org/economicsl/auctions/participants/TokenGenerator.scala similarity index 94% rename from src/main/scala/org/economicsl/auctions/TokenGenerator.scala rename to src/main/scala/org/economicsl/auctions/participants/TokenGenerator.scala index c312f1b..a8c2fe7 100644 --- a/src/main/scala/org/economicsl/auctions/TokenGenerator.scala +++ b/src/main/scala/org/economicsl/auctions/participants/TokenGenerator.scala @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package org.economicsl.auctions +package org.economicsl.auctions.participants import org.economicsl.core.util.UUIDGenerator diff --git a/src/main/scala/org/economicsl/auctions/participants/package.scala b/src/main/scala/org/economicsl/auctions/participants/package.scala new file mode 100644 index 0000000..e2d2473 --- /dev/null +++ b/src/main/scala/org/economicsl/auctions/participants/package.scala @@ -0,0 +1,33 @@ +/* +Copyright (c) 2017 KAPSARC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package org.economicsl.auctions + +import java.util.UUID + + +/** Traits defining an interface for all auction participants. + * + * The auctions library should be agnostic about auction participant behavior and only define a thin + * interface that all implementations of auction participants must satisfy. + * + * @since 0.2.0 + */ +package object participants { + + /* Type alias used to denote a unique (to the auction participant!) identifier for an accepted order. */ + type Token = UUID + +} diff --git a/src/main/scala/org/economicsl/auctions/singleunit/OpenBidAuction.scala b/src/main/scala/org/economicsl/auctions/singleunit/OpenBidSingleUnitAuction.scala similarity index 78% rename from src/main/scala/org/economicsl/auctions/singleunit/OpenBidAuction.scala rename to src/main/scala/org/economicsl/auctions/singleunit/OpenBidSingleUnitAuction.scala index 41124d0..a8a1fe6 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/OpenBidAuction.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/OpenBidSingleUnitAuction.scala @@ -15,6 +15,7 @@ limitations under the License. */ package org.economicsl.auctions.singleunit +import org.economicsl.auctions.QuotingPolicy import org.economicsl.auctions.quotes.{Quote, QuoteRequest} import org.economicsl.auctions.singleunit.clearing.{DiscriminatoryClearingPolicy, UniformClearingPolicy} import org.economicsl.auctions.singleunit.orderbooks.FourHeapOrderBook @@ -32,9 +33,10 @@ import org.economicsl.core.{Currency, Tradable} * @author davidrpugh * @since 0.1.0 */ -abstract class OpenBidAuction[T <: Tradable] - extends Auction[T, OpenBidAuction[T]] { - this: OpenBidAuction[T] => +abstract class OpenBidSingleUnitAuction[T <: Tradable] + extends SingleUnitAuction[T, OpenBidSingleUnitAuction[T]] + with QuotingPolicy[T] { + this: OpenBidSingleUnitAuction[T] => def receive(request: QuoteRequest[T]): Quote = { request.query(orderBook) @@ -43,30 +45,30 @@ abstract class OpenBidAuction[T <: Tradable] } -object OpenBidAuction { +object OpenBidSingleUnitAuction { def withDiscriminatoryClearingPolicy[T <: Tradable] (pricingPolicy: PricingPolicy[T], tickSize: Currency, tradable: T) - : OpenBidAuction[T] = { + : OpenBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithDiscriminatoryClearingPolicy[T](orderBook, pricingPolicy, tickSize, tradable) } def withDiscriminatoryClearingPolicy[T <: Tradable] (pricingPolicy: PricingPolicy[T], tradable: T) - : OpenBidAuction[T] = { + : OpenBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithDiscriminatoryClearingPolicy[T](orderBook, pricingPolicy, 1L, tradable) } def withUniformClearingPolicy[T <: Tradable] (pricingPolicy: PricingPolicy[T], tickSize: Currency, tradable: T) - : OpenBidAuction[T] = { + : OpenBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithUniformClearingPolicy[T](orderBook, pricingPolicy, tickSize, tradable) } - def withUniformClearingPolicy[T <: Tradable](pricingPolicy: PricingPolicy[T], tradable: T): OpenBidAuction[T] = { + def withUniformClearingPolicy[T <: Tradable](pricingPolicy: PricingPolicy[T], tradable: T): OpenBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithUniformClearingPolicy[T](orderBook, pricingPolicy, 1L, tradable) } @@ -77,21 +79,21 @@ object OpenBidAuction { protected val pricingPolicy: PricingPolicy[T], val tickSize: Currency, val tradable: T) - extends OpenBidAuction[T] - with DiscriminatoryClearingPolicy[T, OpenBidAuction[T]] { + extends OpenBidSingleUnitAuction[T] + with DiscriminatoryClearingPolicy[T, OpenBidSingleUnitAuction[T]] { /** Returns an auction of type `A` with a particular pricing policy. */ - def withPricingPolicy(updated: PricingPolicy[T]): OpenBidAuction[T] = { + def withPricingPolicy(updated: PricingPolicy[T]): OpenBidSingleUnitAuction[T] = { new WithDiscriminatoryClearingPolicy[T](orderBook, updated, tickSize, tradable) } /** Returns an auction of type `A` with a particular tick size. */ - def withTickSize(updated: Currency): OpenBidAuction[T] = { + def withTickSize(updated: Currency): OpenBidSingleUnitAuction[T] = { new WithDiscriminatoryClearingPolicy[T](orderBook, pricingPolicy, updated, tradable) } /** Factory method used by sub-classes to create an `Auction` of type `A`. */ - protected def withOrderBook(updated: FourHeapOrderBook[T]): OpenBidAuction[T] = { + protected def withOrderBook(updated: FourHeapOrderBook[T]): OpenBidSingleUnitAuction[T] = { new WithDiscriminatoryClearingPolicy[T](updated, pricingPolicy, tickSize, tradable) } @@ -103,21 +105,21 @@ object OpenBidAuction { protected val pricingPolicy: PricingPolicy[T], val tickSize: Currency, val tradable: T) - extends OpenBidAuction[T] - with UniformClearingPolicy[T, OpenBidAuction[T]] { + extends OpenBidSingleUnitAuction[T] + with UniformClearingPolicy[T, OpenBidSingleUnitAuction[T]] { /** Returns an auction of type `A` with a particular pricing policy. */ - def withPricingPolicy(updated: PricingPolicy[T]): OpenBidAuction[T] = { + def withPricingPolicy(updated: PricingPolicy[T]): OpenBidSingleUnitAuction[T] = { new WithUniformClearingPolicy[T](orderBook, updated, tickSize, tradable) } /** Returns an auction of type `A` with a particular tick size. */ - def withTickSize(updated: Currency): OpenBidAuction[T] = { + def withTickSize(updated: Currency): OpenBidSingleUnitAuction[T] = { new WithUniformClearingPolicy[T](orderBook, pricingPolicy, updated, tradable) } /** Factory method used by sub-classes to create an `Auction` of type `A`. */ - protected def withOrderBook(updated: FourHeapOrderBook[T]): OpenBidAuction[T] = { + protected def withOrderBook(updated: FourHeapOrderBook[T]): OpenBidSingleUnitAuction[T] = { new WithUniformClearingPolicy[T](updated, pricingPolicy, tickSize, tradable) } diff --git a/src/main/scala/org/economicsl/auctions/singleunit/SealedBidAuction.scala b/src/main/scala/org/economicsl/auctions/singleunit/SealedBidSingleUnitAuction.scala similarity index 77% rename from src/main/scala/org/economicsl/auctions/singleunit/SealedBidAuction.scala rename to src/main/scala/org/economicsl/auctions/singleunit/SealedBidSingleUnitAuction.scala index 03b809c..4ce3c5b 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/SealedBidAuction.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/SealedBidSingleUnitAuction.scala @@ -21,7 +21,7 @@ import org.economicsl.auctions.singleunit.pricing.PricingPolicy import org.economicsl.core.{Currency, Tradable} -/** Base trait for all "sealed-bid" auction mechanisms. +/** Base class for all "sealed-bid" auction mechanisms. * * @tparam T all `AskOrder` and `BidOrder` instances submitted to the `SealedBidAuction` must be for the same * type of `Tradable`. @@ -31,36 +31,36 @@ import org.economicsl.core.{Currency, Tradable} * @author davidrpugh * @since 0.1.0 */ -abstract class SealedBidAuction[T <: Tradable] - extends Auction[T, SealedBidAuction[T]] { - this: SealedBidAuction[T] => +abstract class SealedBidSingleUnitAuction[T <: Tradable] + extends SingleUnitAuction[T, SealedBidSingleUnitAuction[T]] { + this: SealedBidSingleUnitAuction[T] => } -object SealedBidAuction { +object SealedBidSingleUnitAuction { def withDiscriminatoryClearingPolicy[T <: Tradable] (pricingPolicy: PricingPolicy[T], tickSize: Currency, tradable: T) - : SealedBidAuction[T] = { + : SealedBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithDiscriminatoryClearingPolicy[T](orderBook, pricingPolicy, tickSize, tradable) } def withDiscriminatoryClearingPolicy[T <: Tradable] (pricingPolicy: PricingPolicy[T], tradable: T) - : SealedBidAuction[T] = { + : SealedBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithDiscriminatoryClearingPolicy[T](orderBook, pricingPolicy, 1L, tradable) } def withUniformClearingPolicy[T <: Tradable] (pricingPolicy: PricingPolicy[T], tickSize: Currency, tradable: T) - : SealedBidAuction[T] = { + : SealedBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithUniformClearingPolicy[T](orderBook, pricingPolicy, tickSize, tradable) } - def withUniformClearingPolicy[T <: Tradable](pricingPolicy: PricingPolicy[T], tradable: T): SealedBidAuction[T] = { + def withUniformClearingPolicy[T <: Tradable](pricingPolicy: PricingPolicy[T], tradable: T): SealedBidSingleUnitAuction[T] = { val orderBook = FourHeapOrderBook.empty[T] new WithUniformClearingPolicy[T](orderBook, pricingPolicy, 1L, tradable) } @@ -71,21 +71,21 @@ object SealedBidAuction { protected val pricingPolicy: PricingPolicy[T], val tickSize: Currency, val tradable: T) - extends SealedBidAuction[T] - with DiscriminatoryClearingPolicy[T, SealedBidAuction[T]] { + extends SealedBidSingleUnitAuction[T] + with DiscriminatoryClearingPolicy[T, SealedBidSingleUnitAuction[T]] { /** Returns an auction of type `A` with a particular pricing policy. */ - def withPricingPolicy(updated: PricingPolicy[T]): SealedBidAuction[T] = { + def withPricingPolicy(updated: PricingPolicy[T]): SealedBidSingleUnitAuction[T] = { new WithDiscriminatoryClearingPolicy[T](orderBook, updated, tickSize, tradable) } /** Returns an auction of type `A` with a particular tick size. */ - def withTickSize(updated: Currency): SealedBidAuction[T] = { + def withTickSize(updated: Currency): SealedBidSingleUnitAuction[T] = { new WithDiscriminatoryClearingPolicy[T](orderBook, pricingPolicy, updated, tradable) } /** Factory method used by sub-classes to create an `Auction` of type `A`. */ - protected def withOrderBook(updated: FourHeapOrderBook[T]): SealedBidAuction[T] = { + protected def withOrderBook(updated: FourHeapOrderBook[T]): SealedBidSingleUnitAuction[T] = { new WithDiscriminatoryClearingPolicy[T](updated, pricingPolicy, tickSize, tradable) } @@ -97,21 +97,21 @@ object SealedBidAuction { protected val pricingPolicy: PricingPolicy[T], val tickSize: Currency, val tradable: T) - extends SealedBidAuction[T] - with UniformClearingPolicy[T, SealedBidAuction[T]] { + extends SealedBidSingleUnitAuction[T] + with UniformClearingPolicy[T, SealedBidSingleUnitAuction[T]] { /** Returns an auction of type `A` with a particular pricing policy. */ - def withPricingPolicy(updated: PricingPolicy[T]): SealedBidAuction[T] = { + def withPricingPolicy(updated: PricingPolicy[T]): SealedBidSingleUnitAuction[T] = { new WithUniformClearingPolicy[T](orderBook, updated, tickSize, tradable) } /** Returns an auction of type `A` with a particular tick size. */ - def withTickSize(updated: Currency): SealedBidAuction[T] = { + def withTickSize(updated: Currency): SealedBidSingleUnitAuction[T] = { new WithUniformClearingPolicy[T](orderBook, pricingPolicy, updated, tradable) } /** Factory method used by sub-classes to create an `Auction` of type `A`. */ - protected def withOrderBook(updated: FourHeapOrderBook[T]): SealedBidAuction[T] = { + protected def withOrderBook(updated: FourHeapOrderBook[T]): SealedBidSingleUnitAuction[T] = { new WithUniformClearingPolicy[T](updated, pricingPolicy, tickSize, tradable) } diff --git a/src/main/scala/org/economicsl/auctions/singleunit/Auction.scala b/src/main/scala/org/economicsl/auctions/singleunit/SingleUnitAuction.scala similarity index 87% rename from src/main/scala/org/economicsl/auctions/singleunit/Auction.scala rename to src/main/scala/org/economicsl/auctions/singleunit/SingleUnitAuction.scala index 8e25925..958c6b5 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/Auction.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/SingleUnitAuction.scala @@ -16,11 +16,11 @@ limitations under the License. package org.economicsl.auctions.singleunit import org.economicsl.auctions._ +import org.economicsl.auctions.participants.Token import org.economicsl.auctions.singleunit.orderbooks.FourHeapOrderBook -import org.economicsl.auctions.singleunit.orders.Order +import org.economicsl.auctions.singleunit.orders.SingleUnitOrder import org.economicsl.auctions.singleunit.pricing.PricingPolicy -import org.economicsl.core.util.Timestamper -import org.economicsl.core.{Currency, Tradable} +import org.economicsl.core.Tradable /** Base trait for all auction implementations. @@ -32,12 +32,11 @@ import org.economicsl.core.{Currency, Tradable} * to use the Type class implementation from Java, we would need to develop (and maintain!) separate wrappers for * each auction implementation. */ -trait Auction[T <: Tradable, A <: Auction[T, A]] - extends ReferenceGenerator - with Timestamper { +trait SingleUnitAuction[T <: Tradable, +A <: SingleUnitAuction[T, A]] + extends Auction[T, SingleUnitOrder[T], A] { this: A => - import OrderTracker._ + import org.economicsl.auctions.participants.OrderTracker._ /** Create a new instance of type class `A` whose order book contains all previously submitted `BidOrder` instances * except the `order`. @@ -74,7 +73,7 @@ trait Auction[T <: Tradable, A <: Auction[T, A]] * second element is an instance of type class `A` whose order book contains all submitted `BidOrder` * instances. */ - def insert(kv: (Token, Order[T])): (A, Either[Rejected, Accepted]) = kv match { + def insert(kv: (Token, SingleUnitOrder[T])): (A, Either[Rejected, Accepted]) = kv match { case (token, order) if order.limit.value % tickSize > 0 => val timestamp = currentTimeMillis() // todo not sure that we want to use real time for timestamps! val reason = InvalidTickSize(order, tickSize) @@ -93,22 +92,15 @@ trait Auction[T <: Tradable, A <: Auction[T, A]] (withOrderBook(updatedOrderBook), Right(accepted)) } - def tickSize: Currency - - def tradable: T - /** Returns an auction of type `A` that encapsulates the current auction state but with a new pricing policy. */ def withPricingPolicy(updated: PricingPolicy[T]): A - /** Returns an auction of type `A` the encapsulates the current auction state but with a new tick size. */ - def withTickSize(updated: Currency): A + protected def orderBook: FourHeapOrderBook[T] + + protected def pricingPolicy: PricingPolicy[T] /** Factory method used by sub-classes to create an `A`. */ protected def withOrderBook(updated: FourHeapOrderBook[T]): A - protected val orderBook: FourHeapOrderBook[T] - - protected val pricingPolicy: PricingPolicy[T] - } diff --git a/src/main/scala/org/economicsl/auctions/singleunit/clearing/ClearingPolicy.scala b/src/main/scala/org/economicsl/auctions/singleunit/clearing/ClearingPolicy.scala index 6348d86..23d25b8 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/clearing/ClearingPolicy.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/clearing/ClearingPolicy.scala @@ -1,8 +1,23 @@ +/* +Copyright 2016 David R. Pugh + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package org.economicsl.auctions.singleunit.clearing import org.economicsl.auctions.singleunit.orderbooks.FourHeapOrderBook import org.economicsl.auctions.singleunit.pricing.PricingPolicy -import org.economicsl.auctions.singleunit.Auction +import org.economicsl.auctions.singleunit.SingleUnitAuction import org.economicsl.auctions.SpotContract import org.economicsl.core.{Price, Tradable} @@ -12,7 +27,7 @@ import org.economicsl.core.{Price, Tradable} * @author davidrpugh * @since 0.1.0 */ -sealed trait ClearingPolicy[T <: Tradable, A <: Auction[T, A]] { +sealed trait ClearingPolicy[T <: Tradable, +A <: SingleUnitAuction[T, A]] { this: A => def clear: (A, Option[Stream[SpotContract]]) @@ -25,7 +40,7 @@ sealed trait ClearingPolicy[T <: Tradable, A <: Auction[T, A]] { * @author davidrpugh * @since 0.1.0 */ -trait DiscriminatoryClearingPolicy[T <: Tradable, A <: Auction[T, A]] +trait DiscriminatoryClearingPolicy[T <: Tradable, A <: SingleUnitAuction[T, A]] extends ClearingPolicy[T, A] { this: A => @@ -57,7 +72,7 @@ trait DiscriminatoryClearingPolicy[T <: Tradable, A <: Auction[T, A]] * @author davidrpugh * @since 0.1.0 */ -trait UniformClearingPolicy[T <: Tradable, A <: Auction[T, A]] +trait UniformClearingPolicy[T <: Tradable, A <: SingleUnitAuction[T, A]] extends ClearingPolicy[T, A] { this: A => diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBook.scala b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBook.scala index 58eafe1..2fa228d 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBook.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBook.scala @@ -15,8 +15,9 @@ limitations under the License. */ package org.economicsl.auctions.singleunit.orderbooks -import org.economicsl.auctions.{Reference, Token} -import org.economicsl.auctions.singleunit.orders.{AskOrder, BidOrder, Order} +import org.economicsl.auctions.Reference +import org.economicsl.auctions.participants.Token +import org.economicsl.auctions.singleunit.orders.{SingleUnitAskOrder, SingleUnitBidOrder, SingleUnitOrder} import org.economicsl.core.{Currency, Price, Tradable} @@ -78,8 +79,8 @@ final class FourHeapOrderBook[T <: Tradable] private(val matchedOrders: MatchedO bidPriceQuote.flatMap(bidPrice => askPriceQuote.map(askPrice => bidPrice.value - askPrice.value)) } - def insert(kv: (Reference, (Token, Order[T]))): FourHeapOrderBook[T] = kv match { - case (reference, (token, order: AskOrder[T])) => + def insert(kv: (Reference, (Token, SingleUnitOrder[T]))): FourHeapOrderBook[T] = kv match { + case (reference, (token, order: SingleUnitAskOrder[T])) => (matchedOrders.headOption, unMatchedOrders.bidOrders.headOption) match { case (Some(((_, (_, askOrder)), _)), Some((existing, rationedBidOrder @ (_, bidOrder)))) if order.limit <= bidOrder.limit && askOrder.limit <= bidOrder.limit => @@ -96,7 +97,7 @@ final class FourHeapOrderBook[T <: Tradable] private(val matchedOrders: MatchedO case _ => new FourHeapOrderBook(matchedOrders, unMatchedOrders + (reference -> (token -> order))) } - case (reference, (token, order: BidOrder[T])) => + case (reference, (token, order: SingleUnitBidOrder[T])) => (matchedOrders.headOption, unMatchedOrders.askOrders.headOption) match { case (Some((_, (_, (_, matchedBidOrder)))), Some((existing, rationedAskOrder @ (_, askOrder)))) if order.limit >= askOrder.limit && matchedBidOrder.limit >= askOrder.limit => @@ -121,14 +122,14 @@ final class FourHeapOrderBook[T <: Tradable] private(val matchedOrders: MatchedO * @return * @note if `reference` is not found in this order book, then this order book is returned. */ - def remove(existing: Reference): (FourHeapOrderBook[T], Option[(Token, Order[T])]) = { + def remove(existing: Reference): (FourHeapOrderBook[T], Option[(Token, SingleUnitOrder[T])]) = { val (remainingUnMatchedOrders, removedOrder) = unMatchedOrders - existing removedOrder match { case Some(_) => (new FourHeapOrderBook(matchedOrders, remainingUnMatchedOrders), removedOrder) case None => matchedOrders.get(existing) match { - case Some((_, _: AskOrder[T])) => + case Some((_, _: SingleUnitAskOrder[T])) => val (_, (_, (_, bidOrder))) = matchedOrders.head unMatchedOrders.askOrders.headOption match { case Some(rationedAskOrder@(reference, (_, askOrder))) if bidOrder.limit >= askOrder.limit => @@ -142,7 +143,7 @@ final class FourHeapOrderBook[T <: Tradable] private(val matchedOrders: MatchedO val updatedOrderBook = new FourHeapOrderBook(remainingMatchedOrders, updatedUnMatchedOrders) (updatedOrderBook, Some(removedAskOrder)) } - case Some((_, _: BidOrder[T])) => + case Some((_, _: SingleUnitBidOrder[T])) => val ((_, (_, askOrder)), _) = matchedOrders.head unMatchedOrders.bidOrders.headOption match { case Some(rationedBidOrder@(reference, (_, bidOrder))) if bidOrder.limit >= askOrder.limit => @@ -171,7 +172,7 @@ final class FourHeapOrderBook[T <: Tradable] private(val matchedOrders: MatchedO * `MatchedOrders` instance is non-empty (first element is `None` otherwise), and whose second element is * the residual `FourHeapOrderBook` instance. */ - def splitAtTopMatch: (FourHeapOrderBook[T], Option[((Reference, (Token, AskOrder[T])), (Reference, (Token, BidOrder[T])))]) = { + def splitAtTopMatch: (FourHeapOrderBook[T], Option[((Reference, (Token, SingleUnitAskOrder[T])), (Reference, (Token, SingleUnitBidOrder[T])))]) = { val (remainingMatchedOrders, topMatchedOrders) = matchedOrders.splitAtTopMatch (new FourHeapOrderBook(remainingMatchedOrders, unMatchedOrders), topMatchedOrders) } @@ -201,12 +202,12 @@ final class FourHeapOrderBook[T <: Tradable] private(val matchedOrders: MatchedO object FourHeapOrderBook { def empty[T <: Tradable]: FourHeapOrderBook[T] = { - val matchedOrders = MatchedOrders.empty[T](Order.ordering.reverse, Order.ordering) - val unMatchedOrders = UnMatchedOrders.empty[T](Order.ordering, Order.ordering.reverse) + val matchedOrders = MatchedOrders.empty[T](SingleUnitOrder.ordering.reverse, SingleUnitOrder.ordering) + val unMatchedOrders = UnMatchedOrders.empty[T](SingleUnitOrder.ordering, SingleUnitOrder.ordering.reverse) new FourHeapOrderBook[T](matchedOrders, unMatchedOrders) } - def empty[T <: Tradable](askOrdering: Ordering[AskOrder[T]], bidOrdering: Ordering[BidOrder[T]]): FourHeapOrderBook[T] = { + def empty[T <: Tradable](askOrdering: Ordering[SingleUnitAskOrder[T]], bidOrdering: Ordering[SingleUnitBidOrder[T]]): FourHeapOrderBook[T] = { val matchedOrders = MatchedOrders.empty(askOrdering.reverse, bidOrdering) val unMatchedOrders = UnMatchedOrders.empty(askOrdering, bidOrdering.reverse) new FourHeapOrderBook(matchedOrders, unMatchedOrders) diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/MatchedOrders.scala b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/MatchedOrders.scala index 3ea0f64..4fb281e 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/MatchedOrders.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/MatchedOrders.scala @@ -15,8 +15,9 @@ limitations under the License. */ package org.economicsl.auctions.singleunit.orderbooks -import org.economicsl.auctions.{Reference, Token} -import org.economicsl.auctions.singleunit.orders.{AskOrder, BidOrder, Order} +import org.economicsl.auctions.Reference +import org.economicsl.auctions.participants.Token +import org.economicsl.auctions.singleunit.orders.{SingleUnitAskOrder, SingleUnitBidOrder, SingleUnitOrder} import org.economicsl.core.{Quantity, Tradable} @@ -31,17 +32,17 @@ import org.economicsl.core.{Quantity, Tradable} */ private[orderbooks] final class MatchedOrders[T <: Tradable](askOrders: SortedAskOrders[T], bidOrders: SortedBidOrders[T]) { - type Match = ((Reference, (Token, AskOrder[T])), (Reference, (Token, BidOrder[T]))) + type Match = ((Reference, (Token, SingleUnitAskOrder[T])), (Reference, (Token, SingleUnitBidOrder[T]))) /* If `MatchedOrders` becomes public, then these should be changes to require!*/ assert(askOrders.numberUnits == bidOrders.numberUnits) assert(invariantsHold, "Limit price of the best `BidOrder` must exceed the limit price of the best `AskOrder`.") /** The ordering used to sort the `AskOrder` instances contained in this `MatchedOrders` instance. */ - val askOrdering: Ordering[(Reference, (Token, AskOrder[T]))] = askOrders.ordering + val askOrdering: Ordering[(Reference, (Token, SingleUnitAskOrder[T]))] = askOrders.ordering /** The ordering used to sort the `BidOrder` instances contained in this `MatchedOrders` instance. */ - val bidOrdering: Ordering[(Reference, (Token, BidOrder[T]))] = bidOrders.ordering + val bidOrdering: Ordering[(Reference, (Token, SingleUnitBidOrder[T]))] = bidOrders.ordering val numberUnits: Quantity = askOrders.numberUnits // or bidOrders.numberUnits! @@ -52,7 +53,7 @@ private[orderbooks] final class MatchedOrders[T <: Tradable](askOrders: SortedAs * @return a new `MatchedOrders` instance that contains all of the `AskOrder` and `BidOrder` instances of this * instance and that also contains the matched pair of `orders`. */ - def + (kv1: (Reference, (Token, AskOrder[T])), kv2: (Reference, (Token, BidOrder[T]))): MatchedOrders[T] = { + def + (kv1: (Reference, (Token, SingleUnitAskOrder[T])), kv2: (Reference, (Token, SingleUnitBidOrder[T]))): MatchedOrders[T] = { new MatchedOrders(askOrders + kv1, bidOrders + kv2) } @@ -62,7 +63,7 @@ private[orderbooks] final class MatchedOrders[T <: Tradable](askOrders: SortedAs * @return a new `MatchedOrders` instance that contains all of the `AskOrder` and `BidOrder` instances of this * instance but that does not contain the matched pair of `orders`. */ - def - (reference: Reference): (MatchedOrders[T], Option[((Token, Order[T]), (Reference, (Token, Order[T])))]) = { + def - (reference: Reference): (MatchedOrders[T], Option[((Token, SingleUnitOrder[T]), (Reference, (Token, SingleUnitOrder[T])))]) = { val (remainingAskOrders, removedAskOrder) = askOrders - reference removedAskOrder match { case Some(askOrder) => @@ -87,15 +88,15 @@ private[orderbooks] final class MatchedOrders[T <: Tradable](askOrders: SortedAs */ def contains(reference: Reference): Boolean = askOrders.contains(reference) || bidOrders.contains(reference) - def get(reference: Reference): Option[(Token, Order[T])] = { + def get(reference: Reference): Option[(Token, SingleUnitOrder[T])] = { askOrders.get(reference).orElse(bidOrders.get(reference)) } - def head: ((Reference, (Token, AskOrder[T])), (Reference, (Token, BidOrder[T]))) = { + def head: ((Reference, (Token, SingleUnitAskOrder[T])), (Reference, (Token, SingleUnitBidOrder[T]))) = { (askOrders.head, bidOrders.head) } - def headOption: Option[((Reference, (Token, AskOrder[T])), (Reference, (Token, BidOrder[T])))] = { + def headOption: Option[((Reference, (Token, SingleUnitAskOrder[T])), (Reference, (Token, SingleUnitBidOrder[T])))] = { askOrders.headOption.flatMap(askOrder => bidOrders.headOption.map(bidOrder => (askOrder, bidOrder))) } @@ -106,13 +107,13 @@ private[orderbooks] final class MatchedOrders[T <: Tradable](askOrders: SortedAs * @return a new `MatchedOrders` instance that contains all of the `AskOrder` except the `reference` `AskOrder` * instance and that also contains the `kv` mapping `(Reference, (Token, AskOrder))`. */ - def replace(existing: Reference, incoming: (Reference, (Token, Order[T]))): (MatchedOrders[T], (Token, Order[T])) = { + def replace(existing: Reference, incoming: (Reference, (Token, SingleUnitOrder[T]))): (MatchedOrders[T], (Token, SingleUnitOrder[T])) = { incoming match { - case (reference, (token, order: AskOrder[T])) => + case (reference, (token, order: SingleUnitAskOrder[T])) => val (remainingAskOrders, Some(removedAskOrder)) = askOrders - existing val updatedAskOrders = remainingAskOrders + (reference -> (token -> order)) (new MatchedOrders(updatedAskOrders, bidOrders), removedAskOrder) - case (reference, (token, order: BidOrder[T])) => + case (reference, (token, order: SingleUnitBidOrder[T])) => val (remainingBidOrders, Some(removedBidOrder)) = bidOrders - existing val updatedBidOrders = remainingBidOrders + (reference -> (token -> order)) (new MatchedOrders(askOrders, updatedBidOrders), removedBidOrder) @@ -163,7 +164,7 @@ object MatchedOrders { * based on `limit` price; the heap used to store store the `BidOrder` instances is * ordered from low to high based on `limit` price. */ - def empty[T <: Tradable](askOrdering: Ordering[AskOrder[T]], bidOrdering: Ordering[BidOrder[T]]): MatchedOrders[T] = { + def empty[T <: Tradable](askOrdering: Ordering[SingleUnitAskOrder[T]], bidOrdering: Ordering[SingleUnitBidOrder[T]]): MatchedOrders[T] = { new MatchedOrders(SortedAskOrders.empty(askOrdering), SortedBidOrders.empty(bidOrdering)) } diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedAskOrders.scala b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedAskOrders.scala index 4e1f508..0230640 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedAskOrders.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedAskOrders.scala @@ -15,8 +15,9 @@ limitations under the License. */ package org.economicsl.auctions.singleunit.orderbooks -import org.economicsl.auctions.{Reference, Token} -import org.economicsl.auctions.singleunit.orders.AskOrder +import org.economicsl.auctions.Reference +import org.economicsl.auctions.participants.Token +import org.economicsl.auctions.singleunit.orders.SingleUnitAskOrder import org.economicsl.core.{Quantity, Tradable} import scala.collection.immutable @@ -34,12 +35,12 @@ import scala.collection.immutable * @author davidrpugh * @since 0.1.0 */ -final class SortedAskOrders[T <: Tradable] private(orders: Map[Reference, (Token, AskOrder[T])], - sortedOrders: immutable.TreeSet[(Reference, (Token, AskOrder[T]))], +final class SortedAskOrders[T <: Tradable] private(orders: Map[Reference, (Token, SingleUnitAskOrder[T])], + sortedOrders: immutable.TreeSet[(Reference, (Token, SingleUnitAskOrder[T]))], val numberUnits: Quantity) { /** The ordering used to sort the `AskOrder` instances contained in this `SortedAskOrders` instance. */ - val ordering: Ordering[(Reference, (Token, AskOrder[T]))] = sortedOrders.ordering + val ordering: Ordering[(Reference, (Token, SingleUnitAskOrder[T]))] = sortedOrders.ordering /** Create a new `SortedAskOrders` instance containing the additional `AskOrder`. * @@ -47,7 +48,7 @@ final class SortedAskOrders[T <: Tradable] private(orders: Map[Reference, (Token * @return a new `SortedAskOrder` instance that contains all of the `AskOrder` instances of this instance and that * also contains the `order`. */ - def + (kv: (Reference, (Token, AskOrder[T]))): SortedAskOrders[T] = kv match { + def + (kv: (Reference, (Token, SingleUnitAskOrder[T]))): SortedAskOrders[T] = kv match { case (_, (_, order)) => new SortedAskOrders(orders + kv, sortedOrders + kv, numberUnits + order.quantity) } @@ -57,7 +58,7 @@ final class SortedAskOrders[T <: Tradable] private(orders: Map[Reference, (Token * @param reference * @return */ - def - (reference: Reference): (SortedAskOrders[T], Option[(Token, AskOrder[T])]) = { + def - (reference: Reference): (SortedAskOrders[T], Option[(Token, SingleUnitAskOrder[T])]) = { orders.get(reference) match { case Some(kv @ (_, order)) => val remainingOrders = orders - reference @@ -76,7 +77,7 @@ final class SortedAskOrders[T <: Tradable] private(orders: Map[Reference, (Token */ def contains(reference: Reference): Boolean = orders.contains(reference) - def get(reference: Reference): Option[(Token, AskOrder[T])] = { + def get(reference: Reference): Option[(Token, SingleUnitAskOrder[T])] = { orders.get(reference) } @@ -84,13 +85,13 @@ final class SortedAskOrders[T <: Tradable] private(orders: Map[Reference, (Token * * @return the first the first key-value mapping contained in this `SortedAskOrders` instance. */ - def head: (Reference, (Token, AskOrder[T])) = sortedOrders.head + def head: (Reference, (Token, SingleUnitAskOrder[T])) = sortedOrders.head /** Optionally selects the first key-value mapping contained in this `SortedAskOrders` instance. * * @return Some key-value mapping if this `SortedAskOrders` instance is non empty; `None` otherwise. */ - def headOption: Option[(Reference, (Token, AskOrder[T]))] = sortedOrders.headOption + def headOption: Option[(Reference, (Token, SingleUnitAskOrder[T]))] = sortedOrders.headOption /** Tests whether this `SortedAskOrder` instance is empty. * @@ -98,7 +99,7 @@ final class SortedAskOrders[T <: Tradable] private(orders: Map[Reference, (Token */ def isEmpty: Boolean = sortedOrders.isEmpty - def splitOffTopOrder: (SortedAskOrders[T], Option[(Reference, (Token, AskOrder[T]))]) = { + def splitOffTopOrder: (SortedAskOrders[T], Option[(Reference, (Token, SingleUnitAskOrder[T]))]) = { headOption match { case Some((reference, (_, askOrder))) => val remainingOrders = orders - reference @@ -131,10 +132,10 @@ object SortedAskOrders { * @tparam T all `AskOrder` instances stored in the heap should be for the same type of `Tradable`. * @return an instance of `SortedAskOrders`. */ - def empty[T <: Tradable](ordering: Ordering[AskOrder[T]]): SortedAskOrders[T] = { - val existing = immutable.HashMap.empty[Reference, (Token, AskOrder[T])] - val byAskOrder = Ordering.by[(Reference, (Token, AskOrder[T])), AskOrder[T]]{ case (_, (_, order)) => order }(ordering) - val sorted = immutable.TreeSet.empty[(Reference, (Token, AskOrder[T]))](byAskOrder) + def empty[T <: Tradable](ordering: Ordering[SingleUnitAskOrder[T]]): SortedAskOrders[T] = { + val existing = immutable.HashMap.empty[Reference, (Token, SingleUnitAskOrder[T])] + val byAskOrder = Ordering.by[(Reference, (Token, SingleUnitAskOrder[T])), SingleUnitAskOrder[T]]{ case (_, (_, order)) => order }(ordering) + val sorted = immutable.TreeSet.empty[(Reference, (Token, SingleUnitAskOrder[T]))](byAskOrder) new SortedAskOrders(existing, sorted, Quantity.zero) } diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedBidOrders.scala b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedBidOrders.scala index d5b96c2..6673c94 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedBidOrders.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/SortedBidOrders.scala @@ -15,8 +15,9 @@ limitations under the License. */ package org.economicsl.auctions.singleunit.orderbooks -import org.economicsl.auctions.{Reference, Token} -import org.economicsl.auctions.singleunit.orders.BidOrder +import org.economicsl.auctions.Reference +import org.economicsl.auctions.participants.Token +import org.economicsl.auctions.singleunit.orders.SingleUnitBidOrder import org.economicsl.core.{Quantity, Tradable} import scala.collection.immutable @@ -34,12 +35,12 @@ import scala.collection.immutable * @author davidrpugh * @since 0.1.0 */ -final class SortedBidOrders[T <: Tradable] private(orders: Map[Reference, (Token, BidOrder[T])], - sortedOrders: immutable.TreeSet[(Reference, (Token, BidOrder[T]))], +final class SortedBidOrders[T <: Tradable] private(orders: Map[Reference, (Token, SingleUnitBidOrder[T])], + sortedOrders: immutable.TreeSet[(Reference, (Token, SingleUnitBidOrder[T]))], val numberUnits: Quantity) { /** The ordering used to sort the `BidOrder` instances contained in this `SortedBidOrders` instance. */ - val ordering: Ordering[(Reference, (Token, BidOrder[T]))] = sortedOrders.ordering + val ordering: Ordering[(Reference, (Token, SingleUnitBidOrder[T]))] = sortedOrders.ordering /** Create a new `SortedBidOrders` instance containing the additional `BidOrder`. * @@ -47,7 +48,7 @@ final class SortedBidOrders[T <: Tradable] private(orders: Map[Reference, (Token * @return a new `SortedBidOrder` instance that contains all of the `BidOrder` instances of this instance and that * also contains the `order`. */ - def + (kv: (Reference, (Token, BidOrder[T]))): SortedBidOrders[T] = { + def + (kv: (Reference, (Token, SingleUnitBidOrder[T]))): SortedBidOrders[T] = { val (_, (_, order)) = kv new SortedBidOrders(orders + kv, sortedOrders + kv, numberUnits + order.quantity) } @@ -57,7 +58,7 @@ final class SortedBidOrders[T <: Tradable] private(orders: Map[Reference, (Token * @param reference * @return */ - def - (reference: Reference): (SortedBidOrders[T], Option[(Token, BidOrder[T])]) = { + def - (reference: Reference): (SortedBidOrders[T], Option[(Token, SingleUnitBidOrder[T])]) = { orders.get(reference) match { case Some(kv @ (_, order)) => val remainingOrders = orders - reference @@ -76,7 +77,7 @@ final class SortedBidOrders[T <: Tradable] private(orders: Map[Reference, (Token */ def contains(reference: Reference): Boolean = orders.contains(reference) - def get(reference: Reference): Option[(Token, BidOrder[T])] = { + def get(reference: Reference): Option[(Token, SingleUnitBidOrder[T])] = { orders.get(reference) } @@ -84,13 +85,13 @@ final class SortedBidOrders[T <: Tradable] private(orders: Map[Reference, (Token * * @return the first `BidOrder` instance contained in this `SortedBidOrders` instance. */ - def head: (Reference, (Token, BidOrder[T])) = sortedOrders.head + def head: (Reference, (Token, SingleUnitBidOrder[T])) = sortedOrders.head /** Optionally selects the first `BidOrder` instance contained in this `SortedBidOrders` instance. * * @return Some `BidOrder` instance if this `SortedBidOrders` instance is non empty; `None` otherwise. */ - def headOption: Option[(Reference, (Token, BidOrder[T]))] = sortedOrders.headOption + def headOption: Option[(Reference, (Token, SingleUnitBidOrder[T]))] = sortedOrders.headOption /** Tests whether this `SortedBidOrder` instance is empty. * @@ -98,7 +99,7 @@ final class SortedBidOrders[T <: Tradable] private(orders: Map[Reference, (Token */ def isEmpty: Boolean = sortedOrders.isEmpty - def splitOffTopOrder: (SortedBidOrders[T], Option[(Reference, (Token, BidOrder[T]))]) = { + def splitOffTopOrder: (SortedBidOrders[T], Option[(Reference, (Token, SingleUnitBidOrder[T]))]) = { headOption match { case Some((reference, (_, askOrder))) => val remainingOrders = orders - reference @@ -131,10 +132,10 @@ object SortedBidOrders { * @tparam T all `BidOrder` instances stored in the heap should be for the same type of `Tradable`. * @return an instance of `SortedBidOrders`. */ - def empty[T <: Tradable](ordering: Ordering[BidOrder[T]]): SortedBidOrders[T] = { - val orders = immutable.HashMap.empty[Reference, (Token, BidOrder[T])] - val byBidOrder = Ordering.by[(Reference, (Token, BidOrder[T])), BidOrder[T]]{ case (_, (_, order)) => order }(ordering) - val sortedOrders = immutable.TreeSet.empty[(Reference, (Token, BidOrder[T]))](byBidOrder) + def empty[T <: Tradable](ordering: Ordering[SingleUnitBidOrder[T]]): SortedBidOrders[T] = { + val orders = immutable.HashMap.empty[Reference, (Token, SingleUnitBidOrder[T])] + val byBidOrder = Ordering.by[(Reference, (Token, SingleUnitBidOrder[T])), SingleUnitBidOrder[T]]{ case (_, (_, order)) => order }(ordering) + val sortedOrders = immutable.TreeSet.empty[(Reference, (Token, SingleUnitBidOrder[T]))](byBidOrder) new SortedBidOrders(orders, sortedOrders, Quantity.zero) } diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/UnMatchedOrders.scala b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/UnMatchedOrders.scala index 16cb70e..74bf5ee 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/UnMatchedOrders.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orderbooks/UnMatchedOrders.scala @@ -15,8 +15,9 @@ limitations under the License. */ package org.economicsl.auctions.singleunit.orderbooks -import org.economicsl.auctions.{Reference, Token} -import org.economicsl.auctions.singleunit.orders.{AskOrder, BidOrder, Order} +import org.economicsl.auctions.Reference +import org.economicsl.auctions.participants.Token +import org.economicsl.auctions.singleunit.orders.{SingleUnitAskOrder, SingleUnitBidOrder, SingleUnitOrder} import org.economicsl.core.Tradable @@ -35,10 +36,10 @@ final class UnMatchedOrders[T <: Tradable] private(val askOrders: SortedAskOrder require(heapsNotCrossed, "Limit price of best `BidOrder` must not exceed the limit price of the best `AskOrder`.") /** The ordering used to sort the `AskOrder` instances contained in this `UnMatchedOrders` instance. */ - val askOrdering: Ordering[(Reference, (Token, AskOrder[T]))] = askOrders.ordering + val askOrdering: Ordering[(Reference, (Token, SingleUnitAskOrder[T]))] = askOrders.ordering /** The ordering used to sort the `BidOrder` instances contained in this `UnMatchedOrders` instance. */ - val bidOrdering: Ordering[(Reference, (Token, BidOrder[T]))] = bidOrders.ordering + val bidOrdering: Ordering[(Reference, (Token, SingleUnitBidOrder[T]))] = bidOrders.ordering /** Create a new `UnMatchedOrders` instance containing the additional `AskOrder`. * @@ -46,10 +47,10 @@ final class UnMatchedOrders[T <: Tradable] private(val askOrders: SortedAskOrder * @return a new `UnMatchedOrders` instance that contains all of the `AskOrder` instances of this instance and that * also contains the `order`. */ - def + (kv: (Reference, (Token, Order[T]))): UnMatchedOrders[T] = kv match { - case (reference, (token, order: AskOrder[T])) => + def + (kv: (Reference, (Token, SingleUnitOrder[T]))): UnMatchedOrders[T] = kv match { + case (reference, (token, order: SingleUnitAskOrder[T])) => new UnMatchedOrders(askOrders + (reference -> (token -> order)), bidOrders) - case (reference, (token, order: BidOrder[T])) => + case (reference, (token, order: SingleUnitBidOrder[T])) => new UnMatchedOrders(askOrders, bidOrders + (reference -> (token -> order))) } @@ -58,7 +59,7 @@ final class UnMatchedOrders[T <: Tradable] private(val askOrders: SortedAskOrder * @param reference * @return a tuple whose first element is ??? and whose second element is ??? */ - def - (reference: Reference): (UnMatchedOrders[T], Option[(Token, Order[T])]) = { + def - (reference: Reference): (UnMatchedOrders[T], Option[(Token, SingleUnitOrder[T])]) = { val (remainingAskOrders, removedAskOrder) = askOrders - reference removedAskOrder match { case Some(_) => @@ -76,7 +77,7 @@ final class UnMatchedOrders[T <: Tradable] private(val askOrders: SortedAskOrder */ def contains(reference: Reference): Boolean = askOrders.contains(reference) || bidOrders.contains(reference) - def get(reference: Reference): Option[(Token, Order[T])] = { + def get(reference: Reference): Option[(Token, SingleUnitOrder[T])] = { askOrders.get(reference).orElse(bidOrders.get(reference)) } @@ -110,7 +111,7 @@ object UnMatchedOrders { * based on `limit` price; the heap used to store store the `BidOrder` instances is * ordered from high to low based on `limit` price. */ - def empty[T <: Tradable](askOrdering: Ordering[AskOrder[T]], bidOrdering: Ordering[BidOrder[T]]): UnMatchedOrders[T] = { + def empty[T <: Tradable](askOrdering: Ordering[SingleUnitAskOrder[T]], bidOrdering: Ordering[SingleUnitBidOrder[T]]): UnMatchedOrders[T] = { new UnMatchedOrders(SortedAskOrders.empty(askOrdering), SortedBidOrders.empty(bidOrdering)) } diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitAskOrder.scala b/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitAskOrder.scala index f5661b8..487e426 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitAskOrder.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitAskOrder.scala @@ -29,7 +29,7 @@ import org.economicsl.core.{Price, Tradable} * @author davidrpugh * @since 0.1.0 */ -class LimitAskOrder[+T <: Tradable](val issuer: UUID, val limit: Price, val tradable: T) extends AskOrder[T] +class LimitAskOrder[+T <: Tradable](val issuer: UUID, val limit: Price, val tradable: T) extends SingleUnitAskOrder[T] /** Companion object for `LimitAskOrder`. diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitBidOrder.scala b/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitBidOrder.scala index 93de160..85259fe 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitBidOrder.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orders/LimitBidOrder.scala @@ -29,7 +29,7 @@ import org.economicsl.core.{Price, Tradable} * @author davidrpugh * @since 0.1.0 */ -class LimitBidOrder[+T <: Tradable](val issuer: UUID, val limit: Price, val tradable: T) extends BidOrder[T] +class LimitBidOrder[+T <: Tradable](val issuer: UUID, val limit: Price, val tradable: T) extends SingleUnitBidOrder[T] /** Companion object for `LimitBidOrder`. diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketAskOrder.scala b/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketAskOrder.scala index 327df72..e187d6d 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketAskOrder.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketAskOrder.scala @@ -28,7 +28,7 @@ import org.economicsl.core.{Price, Tradable} * @author davidrpugh * @since 0.1.0 */ -class MarketAskOrder[+T <: Tradable](val issuer: UUID, val tradable: T) extends AskOrder[T] { +class MarketAskOrder[+T <: Tradable](val issuer: UUID, val tradable: T) extends SingleUnitAskOrder[T] { val limit: Price = Price.MinValue diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketBidOrder.scala b/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketBidOrder.scala index 07e54cd..78dfdfc 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketBidOrder.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orders/MarketBidOrder.scala @@ -28,7 +28,7 @@ import org.economicsl.core.{Price, Tradable} * @author davidrpugh * @since 0.1.0 */ -class MarketBidOrder[+T <: Tradable](val issuer: UUID, val tradable: T) extends BidOrder[T] { +class MarketBidOrder[+T <: Tradable](val issuer: UUID, val tradable: T) extends SingleUnitBidOrder[T] { val limit: Price = Price.MaxValue diff --git a/src/main/scala/org/economicsl/auctions/singleunit/orders/Order.scala b/src/main/scala/org/economicsl/auctions/singleunit/orders/SingleUnitOrder.scala similarity index 71% rename from src/main/scala/org/economicsl/auctions/singleunit/orders/Order.scala rename to src/main/scala/org/economicsl/auctions/singleunit/orders/SingleUnitOrder.scala index d9328cd..cdd282f 100644 --- a/src/main/scala/org/economicsl/auctions/singleunit/orders/Order.scala +++ b/src/main/scala/org/economicsl/auctions/singleunit/orders/SingleUnitOrder.scala @@ -15,7 +15,7 @@ limitations under the License. */ package org.economicsl.auctions.singleunit.orders -import org.economicsl.auctions.{Contract, SingleUnit} +import org.economicsl.auctions.{Order, SingleUnit} import org.economicsl.core.Tradable import play.api.libs.json.{JsValue, Json, Writes} @@ -26,7 +26,7 @@ import play.api.libs.json.{JsValue, Json, Writes} * @author davidrpugh * @since 0.1.0 */ -sealed trait Order[+T <: Tradable] extends Contract with SingleUnit[T] +sealed trait SingleUnitOrder[+T <: Tradable] extends Order[T] with SingleUnit[T] /** Companion object for the `Order` trait. @@ -36,9 +36,9 @@ sealed trait Order[+T <: Tradable] extends Contract with SingleUnit[T] * @author davidrpugh * @since 0.1.0 */ -object Order { +object SingleUnitOrder { - implicit def writes[O <: Order[_ <: Tradable]]: Writes[O] = new Writes[O] { + implicit def writes[O <: SingleUnitOrder[_ <: Tradable]]: Writes[O] = new Writes[O] { def writes(o: O): JsValue = Json.obj( "issuer" -> o.issuer, "limit" -> o.limit, @@ -52,7 +52,7 @@ object Order { * @tparam O the sub-type of `Order` that is being ordered. * @return an `Ordering` defined over `Order` instances. */ - implicit def ordering[O <: Order[_ <: Tradable]]: Ordering[O] = { + implicit def ordering[O <: SingleUnitOrder[_ <: Tradable]]: Ordering[O] = { SingleUnit.ordering } @@ -65,12 +65,12 @@ object Order { * @author davidrpugh * @since 0.1.0 */ -trait AskOrder[+T <: Tradable] extends Order[T] +trait SingleUnitAskOrder[+T <: Tradable] extends SingleUnitOrder[T] -object AskOrder { +object SingleUnitAskOrder { - implicit def writes[T <: Tradable]: Writes[AskOrder[T]] = Order.writes[AskOrder[T]] + implicit def writes[T <: Tradable]: Writes[SingleUnitAskOrder[T]] = SingleUnitOrder.writes[SingleUnitAskOrder[T]] } @@ -81,11 +81,11 @@ object AskOrder { * @author davidrpugh * @since 0.1.0 */ -trait BidOrder[+T <: Tradable] extends Order[T] +trait SingleUnitBidOrder[+T <: Tradable] extends SingleUnitOrder[T] -object BidOrder { +object SingleUnitBidOrder { - implicit def writes[T <: Tradable]: Writes[BidOrder[T]] = Order.writes[BidOrder[T]] + implicit def writes[T <: Tradable]: Writes[SingleUnitBidOrder[T]] = SingleUnitOrder.writes[SingleUnitBidOrder[T]] } \ No newline at end of file diff --git a/src/test/scala/org/economicsl/auctions/actors/AuctionParticipantActorSpec.scala b/src/test/scala/org/economicsl/auctions/actors/AuctionParticipantActorSpec.scala index 42ead87..5a042d0 100644 --- a/src/test/scala/org/economicsl/auctions/actors/AuctionParticipantActorSpec.scala +++ b/src/test/scala/org/economicsl/auctions/actors/AuctionParticipantActorSpec.scala @@ -19,8 +19,9 @@ import java.util.UUID import akka.actor.ActorSystem import akka.testkit.{TestActorRef, TestKit} -import org.economicsl.auctions.OrderTracker.{Accepted, CanceledByIssuer} -import org.economicsl.auctions.{ReferenceGenerator, TestTradable, TokenGenerator} +import org.economicsl.auctions.participants.OrderTracker.{Accepted, CanceledByIssuer} +import org.economicsl.auctions.participants.TokenGenerator +import org.economicsl.auctions.{ReferenceGenerator, TestTradable} import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder} import org.economicsl.core.Price import org.economicsl.core.util.Timestamper diff --git a/src/test/scala/org/economicsl/auctions/actors/TestAuctionParticipantActor.scala b/src/test/scala/org/economicsl/auctions/actors/TestAuctionParticipantActor.scala index 36b5b8c..5f2ed60 100644 --- a/src/test/scala/org/economicsl/auctions/actors/TestAuctionParticipantActor.scala +++ b/src/test/scala/org/economicsl/auctions/actors/TestAuctionParticipantActor.scala @@ -17,14 +17,21 @@ package org.economicsl.auctions.actors import akka.actor.{ActorRef, Props} import org.economicsl.auctions.Issuer -import org.economicsl.auctions.actors.AuctionParticipantActor.AuctionProtocol -import org.economicsl.auctions.singleunit.TestAuctionParticipant +import org.economicsl.auctions.participants.TestAuctionParticipant +import org.economicsl.core.Tradable +/** + * + * @param auctionParticipant + * @note there is a coupling between AuctionParticipant auctions field which maps a Tradable to its AuctionProtocol and + * the auctions field of the AuctionParticipantActor which maps the a Tradable to the ActorRef for the + * corresponding AuctionActor. + */ class TestAuctionParticipantActor private(var auctionParticipant: TestAuctionParticipant) extends AuctionParticipantActor[TestAuctionParticipant] { - protected var auctions: Map[ActorRef, AuctionProtocol] = Map.empty[ActorRef, AuctionProtocol] + protected var auctions: Map[Tradable, ActorRef] = Map.empty[Tradable, ActorRef] } @@ -32,7 +39,7 @@ class TestAuctionParticipantActor private(var auctionParticipant: TestAuctionPar object TestAuctionParticipantActor { def props(issuer: Issuer): Props = { - val auctionParticipant = TestAuctionParticipant.withNoOutstandingOrders(issuer) + val auctionParticipant = TestAuctionParticipant(issuer) Props(new TestAuctionParticipantActor(auctionParticipant)) } diff --git a/src/test/scala/org/economicsl/auctions/singleunit/OrderGenerator.scala b/src/test/scala/org/economicsl/auctions/participants/OrderGenerator.scala similarity index 89% rename from src/test/scala/org/economicsl/auctions/singleunit/OrderGenerator.scala rename to src/test/scala/org/economicsl/auctions/participants/OrderGenerator.scala index a29857e..1ae3897 100644 --- a/src/test/scala/org/economicsl/auctions/singleunit/OrderGenerator.scala +++ b/src/test/scala/org/economicsl/auctions/participants/OrderGenerator.scala @@ -13,11 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package org.economicsl.auctions.singleunit +package org.economicsl.auctions.participants import java.util.UUID -import org.economicsl.auctions.{Token, TokenGenerator} import org.economicsl.auctions.singleunit.orders._ import org.economicsl.core.{Price, Tradable} @@ -73,7 +72,7 @@ object OrderGenerator extends TokenGenerator { } - def randomOrder[T <: Tradable](askOrderProbability: Double)(tradable: T, prng: Random): (Token, Order[T]) = { + def randomOrder[T <: Tradable](askOrderProbability: Double)(tradable: T, prng: Random): (Token, SingleUnitOrder[T]) = { if (prng.nextDouble() <= askOrderProbability) { randomAskOrder(tradable, prng) } else { @@ -82,9 +81,9 @@ object OrderGenerator extends TokenGenerator { } - def randomOrders[T <: Tradable](askOrderProbability: Double)(n: Int, tradable: T, prng: Random): Stream[(Token, Order[T])] = { + def randomOrders[T <: Tradable](askOrderProbability: Double)(n: Int, tradable: T, prng: Random): Stream[(Token, SingleUnitOrder[T])] = { @annotation.tailrec - def loop(accumulated: Stream[(Token, Order[T])], remaining: Int): Stream[(Token, Order[T])] = { + def loop(accumulated: Stream[(Token, SingleUnitOrder[T])], remaining: Int): Stream[(Token, SingleUnitOrder[T])] = { if (remaining == 0) { accumulated } else { @@ -92,7 +91,7 @@ object OrderGenerator extends TokenGenerator { loop(order #:: accumulated, remaining - 1) } } - loop(Stream.empty[(Token, Order[T])], n) + loop(Stream.empty[(Token, SingleUnitOrder[T])], n) } diff --git a/src/test/scala/org/economicsl/auctions/singleunit/TestAuctionParticipant.scala b/src/test/scala/org/economicsl/auctions/participants/TestAuctionParticipant.scala similarity index 51% rename from src/test/scala/org/economicsl/auctions/singleunit/TestAuctionParticipant.scala rename to src/test/scala/org/economicsl/auctions/participants/TestAuctionParticipant.scala index a5d2923..d3ebeeb 100644 --- a/src/test/scala/org/economicsl/auctions/singleunit/TestAuctionParticipant.scala +++ b/src/test/scala/org/economicsl/auctions/participants/TestAuctionParticipant.scala @@ -13,17 +13,26 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package org.economicsl.auctions.singleunit +package org.economicsl.auctions.participants +import org.economicsl.auctions.Auction.AuctionProtocol import org.economicsl.auctions._ +import org.economicsl.core.Tradable -class TestAuctionParticipant private(val issuer: Issuer, val outstandingOrders: Map[Token, (Reference, Contract)]) +class TestAuctionParticipant private( + val issuer: Issuer, + protected val auctions: Map[Tradable, AuctionProtocol], + val outstandingOrders: Map[Token, (Reference, Contract)]) extends AuctionParticipant[TestAuctionParticipant] { + protected def withAuctions(updated: Map[Tradable, AuctionProtocol]): TestAuctionParticipant = { + new TestAuctionParticipant(issuer, updated, outstandingOrders) + } + /** Factory method used by sub-classes to create an `A`. */ protected def withOutstandingOrders(updated: Map[Token, (Reference, Contract)]): TestAuctionParticipant = { - new TestAuctionParticipant(issuer, updated) + new TestAuctionParticipant(issuer, auctions, updated) } } @@ -31,9 +40,10 @@ class TestAuctionParticipant private(val issuer: Issuer, val outstandingOrders: object TestAuctionParticipant { - def withNoOutstandingOrders(issuer: Issuer): TestAuctionParticipant = { - val noOutstandingOrders = Map.empty[Token, (Reference, Contract)] - new TestAuctionParticipant(issuer, noOutstandingOrders) + def apply(issuer: Issuer): TestAuctionParticipant = { + val emptyAuctions = Map.empty[Tradable, AuctionProtocol] + val emptyOutstandingOrders = Map.empty[Token, (Reference, Contract)] + new TestAuctionParticipant(issuer, emptyAuctions, emptyOutstandingOrders) } } diff --git a/src/test/scala/org/economicsl/auctions/singleunit/TestOrderTracker.scala b/src/test/scala/org/economicsl/auctions/participants/TestOrderTracker.scala similarity index 90% rename from src/test/scala/org/economicsl/auctions/singleunit/TestOrderTracker.scala rename to src/test/scala/org/economicsl/auctions/participants/TestOrderTracker.scala index ac16b47..a47a5ef 100644 --- a/src/test/scala/org/economicsl/auctions/singleunit/TestOrderTracker.scala +++ b/src/test/scala/org/economicsl/auctions/participants/TestOrderTracker.scala @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -package org.economicsl.auctions.singleunit +package org.economicsl.auctions.participants import org.economicsl.auctions._ @@ -21,7 +21,7 @@ import scala.collection.immutable.HashMap class TestOrderTracker private( - protected val outstandingOrders: Map[Token, (Reference, Contract)]) + val outstandingOrders: Map[Token, (Reference, Contract)]) extends OrderTracker[TestOrderTracker] { /** Factory method used by sub-classes to create an `A`. */ diff --git a/src/test/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBookSpec.scala b/src/test/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBookSpec.scala index dc066ee..fdc2668 100644 --- a/src/test/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBookSpec.scala +++ b/src/test/scala/org/economicsl/auctions/singleunit/orderbooks/FourHeapOrderBookSpec.scala @@ -15,8 +15,8 @@ limitations under the License. */ package org.economicsl.auctions.singleunit.orderbooks -import org.economicsl.auctions.singleunit.OrderGenerator -import org.economicsl.auctions.{Reference, ReferenceGenerator, TestTradable, Token} +import org.economicsl.auctions.participants.{OrderGenerator, Token} +import org.economicsl.auctions.{Reference, ReferenceGenerator, TestTradable} import org.economicsl.auctions.singleunit.orders.{LimitAskOrder, LimitBidOrder} import org.economicsl.core.Quantity import org.scalatest.{FlatSpec, Matchers}