diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/shelf/Uncommitted_changes_before_Update_at_11_08_2020,_22_16_[Default_Changelist]/shelved.patch b/.idea/shelf/Uncommitted_changes_before_Update_at_11_08_2020,_22_16_[Default_Changelist]/shelved.patch
new file mode 100644
index 0000000..e10d09b
--- /dev/null
+++ b/.idea/shelf/Uncommitted_changes_before_Update_at_11_08_2020,_22_16_[Default_Changelist]/shelved.patch
@@ -0,0 +1,132 @@
+Index: main.js
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>const {asda,costco,budgens} = require(\"./marketplace\");\nconst {Market} = require(\"./Market\");\nconst { Buyer } = require(\"./Buyer\");\n\n\nfunction main(){ \n const market = new Market([asda,budgens,costco]);\n let buyer = new Buyer(market);\n let product = \"Apples\";\n let quantity = 10;\n buyerFunctions(product, quantity, buyer);\n // observeMarket(market);\n};\n\nfunction buyerFunctions(product, quantity, buyer){\n console.log(`The best price for ${product} is ${buyer.getBestPrice(product)}`) ;\n console.log(`To completely fill a order of ${quantity} ${product} costs ${buyer.completelyFill(product,quantity)}`) ;\n console.log(`To buy as quickly as possible ${quantity} ${product} costs ${buyer.quicklyFill(product,quantity)}`) ;\n\n}\n\nfunction observeMarket(market){\n market.observable.subscribe( (mkt) => {\n console.log(`The current price of apples are ${market.sellers[0].inventory[\"Apples\"].price}`)});\n}\n\nmain();
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- main.js (revision e6b7c987d84ebdcf143c23238a39a662a5604309)
++++ main.js (date 1597155171121)
+@@ -14,8 +14,8 @@
+
+ function buyerFunctions(product, quantity, buyer){
+ console.log(`The best price for ${product} is ${buyer.getBestPrice(product)}`) ;
+- console.log(`To completely fill a order of ${quantity} ${product} costs ${buyer.completelyFill(product,quantity)}`) ;
+- console.log(`To buy as quickly as possible ${quantity} ${product} costs ${buyer.quicklyFill(product,quantity)}`) ;
++ // console.log(`To completely fill a order of ${quantity} ${product} costs ${buyer.completelyFill(product,quantity)}`) ;
++ // console.log(`To buy as quickly as possible ${quantity} ${product} costs ${buyer.quicklyFill(product,quantity)}`) ;
+
+ }
+
+Index: .idea/workspace.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>\n\n \n \n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n \n 1597136254764\n \n \n 1597136254764\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- .idea/workspace.xml (revision e6b7c987d84ebdcf143c23238a39a662a5604309)
++++ .idea/workspace.xml (date 1597180559733)
+@@ -2,8 +2,8 @@
+
+
+
+-
+-
++
++
+
+
+
+@@ -31,9 +31,10 @@
+
+
+
+-
++
++
+
+-
++
+
+
+
+@@ -47,6 +48,19 @@
+
+
+
++
++
++
++
++
++
++
++
++
++
++
++
++
+
+
+
+@@ -59,6 +73,7 @@
+
+
+
++
+
+
+
+@@ -74,6 +89,7 @@
+ 1597136254764
+
+
++
+
+
+
+@@ -81,22 +97,34 @@
+
+
+
+-
+-
++
++
+
++
++
++
++
++
+
+-
+-
++
++
+
++
+
+-
+-
++
++
+
++
+
+-
+-
++
++
+
++
+
++
++
++
++
+
+
+
diff --git a/.idea/shelf/Uncommitted_changes_before_Update_at_11_08_2020__22_16__Default_Changelist_.xml b/.idea/shelf/Uncommitted_changes_before_Update_at_11_08_2020__22_16__Default_Changelist_.xml
new file mode 100644
index 0000000..93d62ae
--- /dev/null
+++ b/.idea/shelf/Uncommitted_changes_before_Update_at_11_08_2020__22_16__Default_Changelist_.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 208ab54..bc1b403 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -1,10 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -32,12 +57,19 @@
+
+
+
+
+
+
-
+
+
-
+
-
+
@@ -49,8 +81,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -59,10 +104,15 @@
+
+
+
+
+
@@ -75,38 +125,75 @@
1597136254764
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
+
-
-
-
+
+
+
+
-
-
-
+
+
+
+
-
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
diff --git a/Buyer.js b/Buyer.js
index 2d67385..848fa7c 100644
--- a/Buyer.js
+++ b/Buyer.js
@@ -1,99 +1,190 @@
class Buyer {
- constructor(market) {
- this.market = market;
- }
+ constructor(market) {
+ this.market = market;
+ }
- /**
- * Build an order preference table for particular product
- * @param product
- */
- buildOrderPreference(product) {
- let sellers = [];
+ /**
+ * Build an order preference table for particular product
+ * @param product
+ */
+ buildOrderPrefBestPrice(product) {
+ let sellers = [];
- // build up the initial list
- this.market.sellers.forEach((seller, i) => {
- if (seller.inventory.hasOwnProperty(product)) {
- const price = seller.quote(product);
- sellers.push({id: seller.id, price: price, index: i, quantity:seller.inventory[product].quantity})
- }
+ // build up the initial list
+ this.market.sellers.forEach((seller, i) => {
+ if (seller.inventory.hasOwnProperty(product)) {
+ const price = seller.quote(product);
+ sellers.push({id: seller.id, price: price, index: i, quantity: seller.inventory[product].quantity})
+ }
- });
+ });
- // sort by best price
- sellers.sort((a, b) => {
- return a.price - b.price;
- })
+ // sort by best price
+ sellers.sort((a, b) => {
+ return a.price - b.price;
+ })
- return sellers;
- }
-
- /**
- * This method should get the best price for a given product
- * across all sellers
- */
- getBestPrice(product) {
- let lowestPrice = null;
- this.market.sellers.forEach(seller => {
- if (seller.inventory.hasOwnProperty(product)) {
- const price = seller.quote(product);
- if (lowestPrice === null || lowestPrice > price) lowestPrice = price;
- }
-
- });
-
- return lowestPrice || 0;
- }
+ return sellers;
+ }
- /**
- * This method should optimise price when filling an order
- * if the quantity is greater than any single seller can accomodate
- * then the next cheapest seller should be used.
- */
- fillWithBestPrices(product, quantity) {
+ buildOrderPrefFastFill(product) {
+ let sellers = [];
- let wantedQuantity = quantity;
- let sellerPreference = this.buildOrderPreference(product);
+ // build up the initial list
+ this.market.sellers.forEach((seller, i) => {
+ if (seller.inventory.hasOwnProperty(product)) {
+ const price = seller.quote(product);
+ sellers.push({id: seller.id, price: price, index: i, quantity: seller.inventory[product].quantity, deliveryWait:seller.deliveryWait})
+ }
- console.log(sellerPreference);
+ });
- let reciept = [];
+ // sort by best price
+ sellers.sort((a, b) => {
+ return a.deliveryWait - b.deliveryWait;
+ })
- while (sellerPreference.length > 0 && wantedQuantity > 0) {
+ return sellers;
+ }
- let seller = sellerPreference.shift();
+ buildOrderPrefMostFill(product) {
+ let sellers = [];
- let r = this.market.sellers[seller.index].sell(product, wantedQuantity);
- wantedQuantity = (wantedQuantity - r.boughtQuantity) < 0 ? 0 : (wantedQuantity - r.boughtQuantity);
+ // build up the initial list
+ this.market.sellers.forEach((seller, i) => {
+ if (seller.inventory.hasOwnProperty(product)) {
+ const price = seller.quote(product);
+ sellers.push({id: seller.id, price: price, index: i, quantity: seller.inventory[product].quantity, deliveryWait:seller.deliveryWait})
+ }
- reciept.push(r);
+ });
+
+ // sort by best price
+ sellers.sort((a, b) => {
+ return b.quantity - a.quantity;
+ })
+
+ return sellers;
+ }
+
+ /**
+ * This method should get the best price for a given product
+ * across all sellers
+ */
+ getBestPrice(product) {
+ let lowestPrice = null;
+ this.market.sellers.forEach(seller => {
+ if (seller.inventory.hasOwnProperty(product)) {
+ const price = seller.quote(product);
+ if (lowestPrice === null || lowestPrice > price) lowestPrice = price;
+ }
+
+ });
+
+ return lowestPrice || 0;
+ }
+
+
+ /**
+ * This method should optimise price when filling an order
+ * if the quantity is greater than any single seller can accomodate
+ * then the next cheapest seller should be used.
+ */
+ fillWithBestPrices(product, quantity) {
+
+ let total = 0;
+ let wantedQuantity = quantity;
+ let sellerPreference = this.buildOrderPrefBestPrice(product);
+
+ let receipt = [];
+
+ while (sellerPreference.length > 0 && wantedQuantity > 0) {
+
+ let seller = sellerPreference.shift();
+
+ let r = this.market.sellers[seller.index].sell(product, wantedQuantity);
+ wantedQuantity = (wantedQuantity - r.boughtQuantity) < 0 ? 0 : (wantedQuantity - r.boughtQuantity);
+
+ receipt.push(r);
+ }
+
+ if (receipt.length > 1) {
+ total = receipt.reduce((a, cv) => {
+ return (typeof a === 'number' ? a : a.cost) + cv.cost;
+ });
+ } else if (receipt.length === 1) total = receipt[0].cost;
+
+ return total;
+ }
+
+
+ /**
+ * This method should optimise for sellers with the largest inventory when filling an order
+ * if the quantity is greater than any single seller can accomodate
+ * then the next largest seller should be used.
+ * if multiple sellers have the same amount of inventory
+ * you should use the cheaper of the two.
+ */
+ fillWithLargestSellers(product, quantity) {
+ let total = 0;
+ let wantedQuantity = quantity;
+ let sellerPreference = this.buildOrderPrefMostFill(product);
+
+ let receipt = [];
+
+ while (sellerPreference.length > 0 && wantedQuantity > 0) {
+
+ let seller = sellerPreference.shift();
+
+ let r = this.market.sellers[seller.index].sell(product, wantedQuantity);
+ wantedQuantity = (wantedQuantity - r.boughtQuantity) < 0 ? 0 : (wantedQuantity - r.boughtQuantity);
+
+ receipt.push(r);
+ }
+
+ if (receipt.length > 1) {
+ total = receipt.reduce((a, cv) => {
+ return (typeof a === 'number' ? a : a.cost) + cv.cost;
+ });
+ } else if (receipt.length === 1) total = receipt[0].cost;
+
+ return total;
}
- console.log(reciept);
+ /**
+ * This fulfils orders based on time to deliver
+ * @param product
+ * @param quantity
+ * @returns {number}
+ */
+ quicklyFill(product, quantity) {
+ let total = 0;
+ let wantedQuantity = quantity;
+ let sellerPreference = this.buildOrderPrefFastFill(product);
- console.log(reciept.reduce((a, cv) => {
- return a.cost + cv.cost;
- })
+ let receipt = [];
+ while (sellerPreference.length > 0 && wantedQuantity > 0) {
- );
+ let seller = sellerPreference.shift();
- throw Error("Not Implemented");
+ let r = this.market.sellers[seller.index].sell(product, wantedQuantity);
+ wantedQuantity = (wantedQuantity - r.boughtQuantity) < 0 ? 0 : (wantedQuantity - r.boughtQuantity);
- }
+ receipt.push(r);
+ }
+ if (receipt.length > 1) {
+ total = receipt.reduce((a, cv) => {
+ return (typeof a === 'number' ? a : a.cost) + cv.cost;
+ });
+ } else if (receipt.length === 1) total = receipt[0].cost;
- /**
- * This method should optimise for sellers with the largest inventory when filling an order
- * if the quantity is greater than any single seller can accomodate
- * then the next largest seller should be used.
- * if multiple sellers have the same amount of inventory
- * you should use the cheaper of the two.
- */
- fillWithLargestSellers(product, quantity) {
- throw Error("Not Implemented");
- }
+ return total;
+
+ }
}
module.exports = {Buyer}
diff --git a/Seller.js b/Seller.js
index 67d9134..fd90440 100644
--- a/Seller.js
+++ b/Seller.js
@@ -36,6 +36,7 @@ class Seller {
const ec = getExpectedChange(this.random_generator);
const alpha = inventory.startingQuantity
const beta = inventory.quantity
+ // console.log(`${this.id} alpha: ${alpha} // beta: ${beta} // ec: ${ec}`);
const inv_based_change = Math.log10(beta / alpha) * (-v);
const sentimentChange = inv_based_change + ((ec - 0.5)*v)
return sentimentChange;
@@ -53,7 +54,6 @@ class Seller {
tick() {
- console.log('tick', this);
for (let [product, value] of Object.entries(this.inventory)) {
let inventory = value;
const isReadyForDelivery = (inventory.priceHistory.length % this.deliveryWait) == 0;
diff --git a/main.js b/main.js
index 31ce18c..563cbf3 100644
--- a/main.js
+++ b/main.js
@@ -9,12 +9,12 @@ function main(){
let product = "Apples";
let quantity = 10;
buyerFunctions(product, quantity, buyer);
- // observeMarket(market);
+ observeMarket(market);
};
function buyerFunctions(product, quantity, buyer){
console.log(`The best price for ${product} is ${buyer.getBestPrice(product)}`) ;
- console.log(`To completely fill a order of ${quantity} ${product} costs ${buyer.completelyFill(product,quantity)}`) ;
+ console.log(`To completely fill a order of ${quantity} ${product} costs ${buyer.fillWithBestPrices(product,quantity)}`) ;
console.log(`To buy as quickly as possible ${quantity} ${product} costs ${buyer.quicklyFill(product,quantity)}`) ;
}
diff --git a/tests/buyer.test.js b/tests/buyer.test.js
index 0ae2140..5693e71 100644
--- a/tests/buyer.test.js
+++ b/tests/buyer.test.js
@@ -47,19 +47,19 @@ describe("Buyer", function () {
it("fill 50 apples", () => {
let buyer = new Buyer(market);
- expect(buyer.fillWithBestPrices('Apples', 50)).toEqual(0);
+ expect(buyer.fillWithBestPrices('Apples', 50)).toEqual(233.60268569487857);
});
- it("fill 100 apples", () => {
+ it("unable to fill 10 Kumquat", () => {
let buyer = new Buyer(market);
- expect(buyer.fillWithBestPrices('Apples', 100)).toEqual(0);
+ expect(buyer.fillWithBestPrices('Kumquat', 10)).toEqual(0);
});
- it("fill 1000 apples", () => {
+ it("Large fill 50 apples", () => {
let buyer = new Buyer(market);
- expect(buyer.fillWithBestPrices('Apples', 100)).toEqual(0);
+ expect(buyer. fillWithLargestSellers('Apples', 50)).toEqual(312.5);
});