Price updation
- Update current_price when no seller or buyer available. - Inc price only when sell-orders from rated sellers are available. - User must buy a minimum FLO before placing a sell order unless they are a 'Miner'.
This commit is contained in:
parent
4a92ee7acf
commit
278fc8bcbd
18
src/group.js
18
src/group.js
@ -40,12 +40,18 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.get = () => new Promise((resolve, reject) => {
|
this.get = () => new Promise((resolve, reject) => {
|
||||||
Promise.all([getBuyOrder(), getSellOrder()]).then(results => {
|
Promise.allSettled([getBuyOrder(), getSellOrder()]).then(results => {
|
||||||
resolve({
|
if (results[0].status === "fulfilled" && results[1].status === "fulfilled")
|
||||||
buyOrder: results[0],
|
resolve({
|
||||||
sellOrder: results[1],
|
buyOrder: results[0].value,
|
||||||
null_base: getSellOrder.cache.mode_null
|
sellOrder: results[1].value,
|
||||||
})
|
null_base: getSellOrder.cache.mode_null
|
||||||
|
})
|
||||||
|
else
|
||||||
|
reject({
|
||||||
|
buy: results[0].reason,
|
||||||
|
sell: results[1].reason
|
||||||
|
})
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
124
src/market.js
124
src/market.js
@ -1,6 +1,7 @@
|
|||||||
const group = require("./group");
|
const group = require("./group");
|
||||||
|
const price = require("./price");
|
||||||
|
const MINIMUM_BUY_REQUIREMENT = 0.1;
|
||||||
|
|
||||||
var net_FLO_price; //container for FLO price (from API or by model)
|
|
||||||
var DB; //container for database
|
var DB; //container for database
|
||||||
|
|
||||||
const tokenAPI = {
|
const tokenAPI = {
|
||||||
@ -52,46 +53,8 @@ const tokenAPI = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRates() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
getRates.FLO_USD().then(FLO_rate => {
|
|
||||||
getRates.USD_INR().then(INR_rate => {
|
|
||||||
net_FLO_price = FLO_rate * INR_rate;
|
|
||||||
console.debug('Rates:', FLO_rate, INR_rate, net_FLO_price);
|
|
||||||
resolve(net_FLO_price);
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getRates.FLO_USD = function() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fetch('https://api.coinlore.net/api/ticker/?id=67').then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
response.json()
|
|
||||||
.then(result => resolve(result[0].price_usd))
|
|
||||||
.catch(error => reject(error));
|
|
||||||
} else
|
|
||||||
reject(response.status);
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getRates.USD_INR = function() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fetch('https://api.exchangerate-api.com/v4/latest/usd').then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
response.json()
|
|
||||||
.then(result => resolve(result.rates['INR']))
|
|
||||||
.catch(error => reject(error));
|
|
||||||
} else
|
|
||||||
reject(response.status);
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function returnRates() {
|
function returnRates() {
|
||||||
return net_FLO_price;
|
return price.currentRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSellOrder(floID, quantity, min_price) {
|
function addSellOrder(floID, quantity, min_price) {
|
||||||
@ -102,23 +65,40 @@ function addSellOrder(floID, quantity, min_price) {
|
|||||||
return reject(INVALID(`Invalid quantity (${quantity})`));
|
return reject(INVALID(`Invalid quantity (${quantity})`));
|
||||||
else if (typeof min_price !== "number" || min_price <= 0)
|
else if (typeof min_price !== "number" || min_price <= 0)
|
||||||
return reject(INVALID(`Invalid min_price (${min_price})`));
|
return reject(INVALID(`Invalid min_price (${min_price})`));
|
||||||
DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => {
|
checkSellRequirement().then(_ => {
|
||||||
let total = result.pop()["total"] || 0;
|
DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => {
|
||||||
if (total < quantity)
|
let total = result.pop()["total"] || 0;
|
||||||
return reject(INVALID("Insufficient FLO"));
|
if (total < quantity)
|
||||||
DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => {
|
return reject(INVALID("Insufficient FLO"));
|
||||||
let locked = result.pop()["locked"] || 0;
|
DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => {
|
||||||
let available = total - locked;
|
let locked = result.pop()["locked"] || 0;
|
||||||
if (available < quantity)
|
let available = total - locked;
|
||||||
return reject(INVALID("Insufficient FLO (Some FLO are locked in another sell order)"));
|
if (available < quantity)
|
||||||
DB.query("INSERT INTO SellOrder(floID, quantity, minPrice) VALUES (?, ?, ?)", [floID, quantity, min_price])
|
return reject(INVALID("Insufficient FLO (Some FLO are locked in another sell order)"));
|
||||||
.then(result => resolve("Added SellOrder to DB"))
|
DB.query("INSERT INTO SellOrder(floID, quantity, minPrice) VALUES (?, ?, ?)", [floID, quantity, min_price])
|
||||||
.catch(error => reject(error));
|
.then(result => resolve("Added SellOrder to DB"))
|
||||||
|
.catch(error => reject(error));
|
||||||
|
}).catch(error => reject(error));
|
||||||
}).catch(error => reject(error));
|
}).catch(error => reject(error));
|
||||||
}).catch(error => reject(error));
|
}).catch(error => reject(error));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkSellRequirement(floID) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DB.query("SELECT * FROM Tags WHERE floID=? AND tag=?", [floID, "MINER"]).then(result => {
|
||||||
|
if (result.length)
|
||||||
|
return resolve(true);
|
||||||
|
DB.query("SELECT SUM(quantity) AS brought FROM Transactions WHERE floID=?", [floID]).then(result => {
|
||||||
|
if (result[0].brought >= MINIMUM_BUY_REQUIREMENT)
|
||||||
|
resolve(true);
|
||||||
|
else
|
||||||
|
reject(INVALID(`Sellers required to buy atleast ${MINIMUM_BUY_REQUIREMENT} FLO before placing a sell order unless they are a Miner`));
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function addBuyOrder(floID, quantity, max_price) {
|
function addBuyOrder(floID, quantity, max_price) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floID || !floCrypto.validateAddr(floID))
|
if (!floID || !floCrypto.validateAddr(floID))
|
||||||
@ -171,9 +151,11 @@ function cancelOrder(type, id, floID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initiateCoupling() {
|
function initiateCoupling() {
|
||||||
group.getBestPairs(net_FLO_price)
|
price.getRates().then(cur_rate => {
|
||||||
.then(bestPairQueue => processCoupling(bestPairQueue))
|
group.getBestPairs(cur_rate)
|
||||||
.catch(error => console.error("initiateCoupling", error))
|
.then(bestPairQueue => processCoupling(bestPairQueue))
|
||||||
|
.catch(error => console.error("initiateCoupling", error))
|
||||||
|
}).catch(error => reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
function processCoupling(bestPairQueue) {
|
function processCoupling(bestPairQueue) {
|
||||||
@ -197,10 +179,26 @@ function processCoupling(bestPairQueue) {
|
|||||||
}).catch(error => console.error(error));
|
}).catch(error => console.error(error));
|
||||||
}).catch(error => console.error(error));
|
}).catch(error => console.error(error));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
if (error !== false)
|
let noBuy, noSell;
|
||||||
console.error(error);
|
if (error.buy === undefined)
|
||||||
else
|
noBuy = false;
|
||||||
console.log("No valid orders.");
|
else if (error.buy !== false) {
|
||||||
|
console.error(error.buy);
|
||||||
|
noBuy = null;
|
||||||
|
} else {
|
||||||
|
console.log("No valid buyOrders.");
|
||||||
|
noBuy = true;
|
||||||
|
}
|
||||||
|
if (error.sell === undefined)
|
||||||
|
noSell = false;
|
||||||
|
if (error.sell !== false) {
|
||||||
|
console.error(error.sell);
|
||||||
|
noSell = null;
|
||||||
|
} else {
|
||||||
|
console.log("No valid sellOrders.");
|
||||||
|
noSell = true;
|
||||||
|
}
|
||||||
|
price.noOrder(noBuy, noSell);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,11 +595,8 @@ function confirmWithdrawalRupee() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function periodicProcess() {
|
function periodicProcess() {
|
||||||
let old_rate = net_FLO_price;
|
transactionReCheck();
|
||||||
getRates().then(cur_rate => {
|
initiateCoupling();
|
||||||
transactionReCheck();
|
|
||||||
initiateCoupling();
|
|
||||||
}).catch(error => console.error(error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function transactionReCheck() {
|
function transactionReCheck() {
|
||||||
@ -628,5 +623,6 @@ module.exports = {
|
|||||||
set DB(db) {
|
set DB(db) {
|
||||||
DB = db;
|
DB = db;
|
||||||
group.DB = db;
|
group.DB = db;
|
||||||
|
price.DB = db;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
121
src/price.js
Normal file
121
src/price.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
const MIN_TIME = 1 * 60 * 60 * 1000,
|
||||||
|
DOWN_RATE = 0.2 / 100,
|
||||||
|
UP_RATE = 0.5 / 100,
|
||||||
|
MAX_DOWN_PER_DAY = 4.8 / 100,
|
||||||
|
MAX_UP_PER_DAY = 12 / 100,
|
||||||
|
TOP_RANGE = 10 / 100;
|
||||||
|
|
||||||
|
var DB; //container for database
|
||||||
|
|
||||||
|
var netValue, //container for FLO price (from API or by model)
|
||||||
|
lastTxTime, //container for timestamp of the last tx
|
||||||
|
noBuyOrder,
|
||||||
|
noSellOrder
|
||||||
|
|
||||||
|
var dayInitRate;
|
||||||
|
setInterval(() => dayInitRate = netValue, 24 * 60 * 60 * 1000); //reset the day price every 24 hrs
|
||||||
|
|
||||||
|
//store FLO price in DB every 1 hr
|
||||||
|
setInterval(function storeRate() {
|
||||||
|
DB.query("INSERT INTO priceHistory (price) VALUE (?)", netValue)
|
||||||
|
.then(_ => null).catch(error => console.error(error))
|
||||||
|
})
|
||||||
|
|
||||||
|
/* OLD FUNCTION
|
||||||
|
function getRates() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
getRates.FLO_USD().then(FLO_rate => {
|
||||||
|
getRates.USD_INR().then(INR_rate => {
|
||||||
|
net_FLO_price = FLO_rate * INR_rate;
|
||||||
|
console.debug('Rates:', FLO_rate, INR_rate, net_FLO_price);
|
||||||
|
resolve(net_FLO_price);
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getRates.FLO_USD = function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch('https://api.coinlore.net/api/ticker/?id=67').then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
response.json()
|
||||||
|
.then(result => resolve(result[0].price_usd))
|
||||||
|
.catch(error => reject(error));
|
||||||
|
} else
|
||||||
|
reject(response.status);
|
||||||
|
}).catch(error => reject(error));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getRates.USD_INR = function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch('https://api.exchangerate-api.com/v4/latest/usd').then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
response.json()
|
||||||
|
.then(result => resolve(result.rates['INR']))
|
||||||
|
.catch(error => reject(error));
|
||||||
|
} else
|
||||||
|
reject(response.status);
|
||||||
|
}).catch(error => reject(error));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getRates() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let cur_time = Date.now();
|
||||||
|
if (cur_time - lastTxTime < MIN_TIME) //Minimum time to update not crossed: No update required
|
||||||
|
resolve(netValue);
|
||||||
|
else if (noBuyOrder && noSellOrder) //Both are not available: No update required
|
||||||
|
resolve(netValue);
|
||||||
|
else if (noBuyOrder === null || noSellOrder === null) //An error has occured during last process: No update (might cause price to crash/jump)
|
||||||
|
resolve(netValue);
|
||||||
|
else if (noBuyOrder) {
|
||||||
|
//No Buy, But Sell available: Decrease the price
|
||||||
|
let tmp_val = netValue * (1 - DOWN_RATE);
|
||||||
|
if (tmp_val >= dayInitRate * (1 - MAX_DOWN_PER_DAY))
|
||||||
|
netValue *= tmp_val;
|
||||||
|
resolve(netValue);
|
||||||
|
} else if (noSellOrder) {
|
||||||
|
//No Sell, But Buy available: Increase the price
|
||||||
|
checkForRatedSellers().then(result => {
|
||||||
|
if (result) {
|
||||||
|
let tmp_val = netValue * (1 + UP_RATE)
|
||||||
|
if (tmp_val >= dayInitRate * (1 + MAX_UP_PER_DAY))
|
||||||
|
netValue *= tmp_val;
|
||||||
|
}
|
||||||
|
}).catch(error => console.error(error)).finally(_ => resolve(netValue));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForRatedSellers() {
|
||||||
|
//Check if there are best rated sellers?
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DB.query("SELECT MAX(sellPriority) as maxValue FROM TagList").then(result => {
|
||||||
|
let ratedMin = result[0].maxValue * (1 - TOP_RANGE);
|
||||||
|
DB.query("SELECT COUNT(*) as value FROM SellOrder WHERE floID IN (" +
|
||||||
|
" SELECT Tags.floID FROM Tags INNER JOIN TagList ON Tags.tag = TagList.tag" +
|
||||||
|
" WHERE TagList.sellPriority > ?)", [ratedMin]).then(result => {
|
||||||
|
resolve(result[0].value > 0);
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getRates,
|
||||||
|
set lastTxTime(t) {
|
||||||
|
lastTxTime = t;
|
||||||
|
},
|
||||||
|
set noOrder(buy, sell) {
|
||||||
|
noBuyOrder = buy;
|
||||||
|
noSellOrder = sell;
|
||||||
|
},
|
||||||
|
set DB(db) {
|
||||||
|
DB = db;
|
||||||
|
},
|
||||||
|
get currentRate() {
|
||||||
|
return netValue
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user