From c14f10eade3d7b3cae31ba8d8859ba06bc062d2c Mon Sep 17 00:00:00 2001 From: sairajzero Date: Sat, 30 Oct 2021 21:35:18 +0530 Subject: [PATCH] Use Group priority to get best buy/sell order --- src/group.js | 43 +++++++++++++++----- src/market.js | 108 ++++++++++++++++---------------------------------- 2 files changed, 66 insertions(+), 85 deletions(-) diff --git a/src/group.js b/src/group.js index 3cfb5ed..43d2a1d 100644 --- a/src/group.js +++ b/src/group.js @@ -24,11 +24,38 @@ function getBestPairs(currentRate) { const bestPair = function(tags, currentRate) { + this.get = () => new Promise((resolve, reject) => { + Promise.all([getBuyOrder(), getSellOrder()]).then(results => { + resolve({ + buyOrder: results[0], + sellOrder: results[1] + }) + }).catch(error => reject(error)) + }); + + this.next = () => { + let buy = getBuyOrder.cache, + sell = getSellOrder.cache; + if (buy.cur_order && sell.cur_order) { + if (buy.cur_order.quantity > sell.cur_order.quantity) { + buy.cur_order.quantity -= sell.cur_order.quantity; + sell.cur_order = null; + } else if (buy.cur_order.quantity < sell.cur_order.quantity) { + sell.cur_order.quantity -= buy.cur_order.quantity; + buy.cur_order = null; + } else { + sell.cur_order = null; + buy.cur_order = null; + } + } else + throw Error("No current order found"); + }; + const getSellOrder = () => new Promise((resolve, reject) => { let cache = getSellOrder.cache; if (cache.cur_order) { //If cache already has a pending order verifySellOrder(cache.cur_order, currentRate).then(result => { - cache.cur_order = result.sellOrder; + cache.cur_order = result; resolve(result); }).catch(error => { if (error !== false) @@ -41,7 +68,7 @@ const bestPair = function(tags, currentRate) { }) } else if (cache.orders && cache.orders.length) { //If cache already has orders in priority getTopValidSellOrder(cache.orders, currentRate).then(result => { - cache.cur_order = result.sellOrder; + cache.cur_order = result; resolve(result); }).catch(error => { if (error !== false) @@ -224,20 +251,17 @@ function getTopValidSellOrder(orders, cur_price) { function verifySellOrder(sellOrder, cur_price) { return new Promise((resolve, reject) => { DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY base", [sellOrder.floID]).then(result => { - let rem = Math.min(sellOrder.quantity, maxQuantity), + let rem = sellOrder.quantity, sell_base = 0, - base_quantity = 0, - txQueries = []; + base_quantity = 0; for (let i = 0; i < result.length && rem > 0; i++) { if (rem < result[i].quantity) { - txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]); if (result[i].base) { sell_base += (rem * result[i].base); base_quantity += rem; } rem = 0; } else { - txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]); if (result[i].base) { sell_base += (result[i].quantity * result[i].base); base_quantity += result[i].quantity; @@ -253,10 +277,7 @@ function verifySellOrder(sellOrder, cur_price) { console.warn(`Sell order ${sellOrder.id} is active, but FLO is insufficient`); reject(false); } else - resolve({ - sellOrder, - txQueries - }); + resolve(sellOrder); }).catch(error => reject(error)); }) diff --git a/src/market.js b/src/market.js index 8fa2044..70150d8 100644 --- a/src/market.js +++ b/src/market.js @@ -1,3 +1,5 @@ +const group = require("./group"); + var net_FLO_price; //container for FLO price (from API or by model) var DB; //container for database @@ -168,16 +170,18 @@ function cancelOrder(type, id, floID) { }); } -function matchBuyAndSell() { - let cur_price = net_FLO_price; - //get the best buyer - getBestBuyer(cur_price).then(buyer_best => { - //get the best seller - getBestSeller(buyer_best.quantity, cur_price).then(result => { - let seller_best = result.sellOrder, - txQueries = result.txQueries; - console.debug("Sell:", seller_best.id, "Buy:", buyer_best.id); +function initiateCoupling() { + group.getBestPairs() + .then(bestPairQueue => processCoupling(bestPairQueue)) + .catch(error => reject(error)) +} +function processCoupling(bestPairQueue) { + bestPairQueue.get().then(result => { + let buyer_best = result.buyOrder, + seller_best = result.sellOrder; + console.debug("Sell:", seller_best.id, "Buy:", buyer_best.id); + spendFLO(buyer_best, seller_best).then(txQueries => { //process the Txn var tx_quantity; if (seller_best.quantity > buyer_best.quantity) @@ -189,80 +193,35 @@ function matchBuyAndSell() { updateBalance(seller_best, buyer_best, txQueries, cur_price, tx_quantity); //process txn query in SQL DB.transaction(txQueries).then(results => { + bestPairQueue.next(); console.log(`Transaction was successful! BuyOrder:${buyer_best.id}| SellOrder:${seller_best.id}`); //Since a tx was successful, match again - matchBuyAndSell(); + processCoupling(bestPairQueue); }).catch(error => console.error(error)); }).catch(error => console.error(error)); }).catch(error => console.error(error)); } -function getBestBuyer(cur_price, n = 0) { +function spendFLO(buyOrder, sellOrder) { return new Promise((resolve, reject) => { - DB.query("SELECT * FROM BuyOrder WHERE maxPrice >= ? ORDER BY time_placed LIMIT ?,1", [cur_price, n]).then(result => { - let buyOrder = result.shift(); - if (!buyOrder) - return reject("No valid buyers available"); - DB.query("SELECT rupeeBalance AS bal FROM Cash WHERE floID=?", [buyOrder.floID]).then(result => { - if (result[0].bal < cur_price * buyOrder.quantity) { - //This should not happen unless a buy order is placed when user doesnt have enough rupee balance - console.warn(`Buy order ${buyOrder.id} is active, but rupee# is insufficient`); - getBestBuyer(cur_price, n + 1) - .then(result => resolve(result)) - .catch(error => reject(error)); - } else - resolve(buyOrder); - }).catch(error => reject(error)); - }).catch(error => reject(error)); - }); -} - -function getBestSeller(maxQuantity, cur_price, n = 0) { - return new Promise((resolve, reject) => { - //TODO: Add order conditions for priority. - DB.query("SELECT * FROM SellOrder WHERE minPrice <=? ORDER BY time_placed LIMIT ?,1", [cur_price, n]).then(result => { - let sellOrder = result.shift(); - if (!sellOrder) - return reject("No valid sellers available"); - DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY base", [sellOrder.floID]).then(result => { - let rem = Math.min(sellOrder.quantity, maxQuantity), - sell_base = 0, - base_quantity = 0, - txQueries = []; - for (let i = 0; i < result.length && rem > 0; i++) { - if (rem < result[i].quantity) { - txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]); - if (result[i].base) { - sell_base += (rem * result[i].base); - base_quantity += rem - } - rem = 0; - } else { - txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]); - if (result[i].base) { - sell_base += (result[i].quantity * result[i].base); - base_quantity += result[i].quantity - } - rem -= result[i].quantity; - } + DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY base", [sellOrder.floID]).then(result => { + let rem = Math.min(buyOrder.quantity, sellOrder.quantity), + txQueries = []; + for (let i = 0; i < result.length && rem > 0; i++) { + if (rem < result[i].quantity) { + txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]); + rem = 0; + } else { + txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]); + rem -= result[i].quantity; } - if (base_quantity) - sell_base = sell_base / base_quantity; - if (rem > 0 || sell_base > cur_price) { - //1st condition (rem>0) should not happen (sell order placement was success when insufficient FLO). - if (rem > 0) - console.warn(`Sell order ${sellOrder.id} is active, but FLO is insufficient`); - getBestSeller(maxQuantity, cur_price, n + 1) - .then(result => resolve(result)) - .catch(error => reject(error)); - } else - resolve({ - sellOrder, - txQueries - }); - }).catch(error => reject(error)); + } + if (rem > 0) + reject(`Sell order ${sellOrder.id} is active, but FLO is insufficient`); + else + resolve(txQueries); }).catch(error => reject(error)); - }); + }) } function processBuyOrder(seller_best, buyer_best, txQueries) { @@ -643,7 +602,7 @@ function periodicProcess() { let old_rate = net_FLO_price; getRates().then(cur_rate => { transactionReCheck(); - matchBuyAndSell(); + initiateCoupling(); }).catch(error => console.error(error)); } @@ -669,5 +628,6 @@ module.exports = { periodicProcess, set DB(db) { DB = db; + group.DB = db; } }; \ No newline at end of file