milltest/Buyer.js

191 lines
5.5 KiB
JavaScript
Raw Normal View History

2020-08-11 11:55:43 +00:00
class Buyer {
2020-08-11 23:29:04 +00:00
constructor(market) {
this.market = market;
}
/**
* 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})
}
});
// sort by best price
sellers.sort((a, b) => {
return a.price - b.price;
})
return sellers;
}
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
buildOrderPrefFastFill(product) {
let sellers = [];
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
// 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})
}
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
});
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
// sort by best price
sellers.sort((a, b) => {
return a.deliveryWait - b.deliveryWait;
})
2020-08-11 20:12:17 +00:00
2020-08-11 23:29:04 +00:00
return sellers;
}
buildOrderPrefMostFill(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, deliveryWait:seller.deliveryWait})
}
});
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
// sort by best price
sellers.sort((a, b) => {
return b.quantity - a.quantity;
})
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
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;
}
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
/**
* 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) {
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
let total = 0;
let wantedQuantity = quantity;
let sellerPreference = this.buildOrderPrefBestPrice(product);
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
let receipt = [];
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
while (sellerPreference.length > 0 && wantedQuantity > 0) {
2020-08-11 20:12:17 +00:00
2020-08-11 23:29:04 +00:00
let seller = sellerPreference.shift();
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
let r = this.market.sellers[seller.index].sell(product, wantedQuantity);
wantedQuantity = (wantedQuantity - r.boughtQuantity) < 0 ? 0 : (wantedQuantity - r.boughtQuantity);
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
receipt.push(r);
}
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
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;
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
return total;
2020-08-11 11:55:43 +00:00
}
2020-08-11 20:12:17 +00:00
2020-08-11 23:29:04 +00:00
/**
* 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);
2020-08-11 20:12:17 +00:00
2020-08-11 23:29:04 +00:00
let receipt = [];
2020-08-11 20:12:17 +00:00
2020-08-11 23:29:04 +00:00
while (sellerPreference.length > 0 && wantedQuantity > 0) {
2020-08-11 20:12:17 +00:00
2020-08-11 23:29:04 +00:00
let seller = sellerPreference.shift();
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
let r = this.market.sellers[seller.index].sell(product, wantedQuantity);
wantedQuantity = (wantedQuantity - r.boughtQuantity) < 0 ? 0 : (wantedQuantity - r.boughtQuantity);
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
receipt.push(r);
}
2020-08-11 11:55:43 +00:00
2020-08-11 23:29:04 +00:00
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 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);
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;
}
2020-08-11 11:55:43 +00:00
}
module.exports = {Buyer}