Use Group priority to get best buy/sell order
This commit is contained in:
parent
0e34dcb5e3
commit
c14f10eade
43
src/group.js
43
src/group.js
@ -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));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
108
src/market.js
108
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 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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user