Use Group priority to get best buy/sell order

This commit is contained in:
sairajzero 2021-10-30 21:35:18 +05:30
parent 0e34dcb5e3
commit c14f10eade
2 changed files with 66 additions and 85 deletions

View File

@ -24,11 +24,38 @@ function getBestPairs(currentRate) {
const bestPair = function(tags, 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) => { const getSellOrder = () => new Promise((resolve, reject) => {
let cache = getSellOrder.cache; let cache = getSellOrder.cache;
if (cache.cur_order) { //If cache already has a pending order if (cache.cur_order) { //If cache already has a pending order
verifySellOrder(cache.cur_order, currentRate).then(result => { verifySellOrder(cache.cur_order, currentRate).then(result => {
cache.cur_order = result.sellOrder; cache.cur_order = result;
resolve(result); resolve(result);
}).catch(error => { }).catch(error => {
if (error !== false) 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 } else if (cache.orders && cache.orders.length) { //If cache already has orders in priority
getTopValidSellOrder(cache.orders, currentRate).then(result => { getTopValidSellOrder(cache.orders, currentRate).then(result => {
cache.cur_order = result.sellOrder; cache.cur_order = result;
resolve(result); resolve(result);
}).catch(error => { }).catch(error => {
if (error !== false) if (error !== false)
@ -224,20 +251,17 @@ function getTopValidSellOrder(orders, cur_price) {
function verifySellOrder(sellOrder, cur_price) { function verifySellOrder(sellOrder, cur_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY base", [sellOrder.floID]).then(result => { 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, sell_base = 0,
base_quantity = 0, base_quantity = 0;
txQueries = [];
for (let i = 0; i < result.length && rem > 0; i++) { for (let i = 0; i < result.length && rem > 0; i++) {
if (rem < result[i].quantity) { if (rem < result[i].quantity) {
txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]);
if (result[i].base) { if (result[i].base) {
sell_base += (rem * result[i].base); sell_base += (rem * result[i].base);
base_quantity += rem; base_quantity += rem;
} }
rem = 0; rem = 0;
} else { } else {
txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]);
if (result[i].base) { if (result[i].base) {
sell_base += (result[i].quantity * result[i].base); sell_base += (result[i].quantity * result[i].base);
base_quantity += result[i].quantity; 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`); console.warn(`Sell order ${sellOrder.id} is active, but FLO is insufficient`);
reject(false); reject(false);
} else } else
resolve({ resolve(sellOrder);
sellOrder,
txQueries
});
}).catch(error => reject(error)); }).catch(error => reject(error));
}) })

View File

@ -1,3 +1,5 @@
const group = require("./group");
var net_FLO_price; //container for FLO price (from API or by model) var net_FLO_price; //container for FLO price (from API or by model)
var DB; //container for database var DB; //container for database
@ -168,16 +170,18 @@ function cancelOrder(type, id, floID) {
}); });
} }
function matchBuyAndSell() { function initiateCoupling() {
let cur_price = net_FLO_price; group.getBestPairs()
//get the best buyer .then(bestPairQueue => processCoupling(bestPairQueue))
getBestBuyer(cur_price).then(buyer_best => { .catch(error => reject(error))
//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 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 //process the Txn
var tx_quantity; var tx_quantity;
if (seller_best.quantity > buyer_best.quantity) if (seller_best.quantity > buyer_best.quantity)
@ -189,80 +193,35 @@ function matchBuyAndSell() {
updateBalance(seller_best, buyer_best, txQueries, cur_price, tx_quantity); updateBalance(seller_best, buyer_best, txQueries, cur_price, tx_quantity);
//process txn query in SQL //process txn query in SQL
DB.transaction(txQueries).then(results => { DB.transaction(txQueries).then(results => {
bestPairQueue.next();
console.log(`Transaction was successful! BuyOrder:${buyer_best.id}| SellOrder:${seller_best.id}`); console.log(`Transaction was successful! BuyOrder:${buyer_best.id}| SellOrder:${seller_best.id}`);
//Since a tx was successful, match again //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)); }).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) => { return new Promise((resolve, reject) => {
DB.query("SELECT * FROM BuyOrder WHERE maxPrice >= ? ORDER BY time_placed LIMIT ?,1", [cur_price, n]).then(result => { DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY base", [sellOrder.floID]).then(result => {
let buyOrder = result.shift(); let rem = Math.min(buyOrder.quantity, sellOrder.quantity),
if (!buyOrder) txQueries = [];
return reject("No valid buyers available"); for (let i = 0; i < result.length && rem > 0; i++) {
DB.query("SELECT rupeeBalance AS bal FROM Cash WHERE floID=?", [buyOrder.floID]).then(result => { if (rem < result[i].quantity) {
if (result[0].bal < cur_price * buyOrder.quantity) { txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]);
//This should not happen unless a buy order is placed when user doesnt have enough rupee balance rem = 0;
console.warn(`Buy order ${buyOrder.id} is active, but rupee# is insufficient`); } else {
getBestBuyer(cur_price, n + 1) txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]);
.then(result => resolve(result)) rem -= result[i].quantity;
.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;
}
} }
if (base_quantity) }
sell_base = sell_base / base_quantity; if (rem > 0)
if (rem > 0 || sell_base > cur_price) { reject(`Sell order ${sellOrder.id} is active, but FLO is insufficient`);
//1st condition (rem>0) should not happen (sell order placement was success when insufficient FLO). else
if (rem > 0) resolve(txQueries);
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));
}).catch(error => reject(error)); }).catch(error => reject(error));
}); })
} }
function processBuyOrder(seller_best, buyer_best, txQueries) { function processBuyOrder(seller_best, buyer_best, txQueries) {
@ -643,7 +602,7 @@ function periodicProcess() {
let old_rate = net_FLO_price; let old_rate = net_FLO_price;
getRates().then(cur_rate => { getRates().then(cur_rate => {
transactionReCheck(); transactionReCheck();
matchBuyAndSell(); initiateCoupling();
}).catch(error => console.error(error)); }).catch(error => console.error(error));
} }
@ -669,5 +628,6 @@ module.exports = {
periodicProcess, periodicProcess,
set DB(db) { set DB(db) {
DB = db; DB = db;
group.DB = db;
} }
}; };