141 lines
4.7 KiB
JavaScript
Executable File
141 lines
4.7 KiB
JavaScript
Executable File
// Declare a route
|
|
|
|
|
|
function processHoldingsList(holdings) {
|
|
const stockGroups = {};
|
|
|
|
for (const stock of holdings) {
|
|
if (stock.symbol in stockGroups) {
|
|
stockGroups[stock.symbol].totalCost += stock.boughtPrice * stock.numberOfShares;
|
|
stockGroups[stock.symbol].totalShares += stock.numberOfShares;
|
|
} else {
|
|
stockGroups[stock.symbol] = {
|
|
totalCost: stock.boughtPrice * stock.numberOfShares,
|
|
totalShares: stock.numberOfShares,
|
|
name: stock.name,
|
|
assetType: stock.assetType,
|
|
currentPrice: stock.currentPrice,
|
|
dailyChange: stock.dailyChange,
|
|
sinceBoughtChange: stock.sinceBoughtChange,
|
|
};
|
|
}
|
|
|
|
// Update dailyChange automatically
|
|
stockGroups[stock.symbol].dailyChange = stock.dailyChange;
|
|
stockGroups[stock.symbol].sinceBoughtChange = stock.sinceBoughtChange;
|
|
stockGroups[stock.symbol].currentPrice = stock.currentPrice;
|
|
}
|
|
|
|
const updatedHoldings = [];
|
|
|
|
for (const symbol in stockGroups) {
|
|
const { totalCost, totalShares, name, assetType, currentPrice, dailyChange, sinceBoughtChange } = stockGroups[symbol];
|
|
const finalBoughtPrice = totalCost / totalShares;
|
|
const updatedStock = {
|
|
symbol,
|
|
name,
|
|
assetType,
|
|
boughtPrice: finalBoughtPrice,
|
|
currentPrice,
|
|
dailyChange,
|
|
sinceBoughtChange: Number(((currentPrice/finalBoughtPrice -1) * 100)?.toFixed(2)),
|
|
numberOfShares: totalShares,
|
|
};
|
|
updatedHoldings.push(updatedStock);
|
|
}
|
|
|
|
return updatedHoldings;
|
|
}
|
|
|
|
|
|
module.exports = function (fastify, opts, done) {
|
|
|
|
const pb = opts.pb;
|
|
|
|
fastify.post('/buy-stock', async (request, reply) => {
|
|
|
|
const holidays = ['2024-01-01', '2024-01-15','2024-02-19','2024-03-29','2024-05-27','2024-06-19','2024-07-04','2024-09-02','2024-11-28','2024-12-25'];
|
|
const currentDate = new Date().toISOString().split('T')[0];
|
|
|
|
// Get the current time in the ET time zone
|
|
const etTimeZone = 'America/New_York';
|
|
const currentTime = new Date().toLocaleString('en-US', { timeZone: etTimeZone });
|
|
|
|
// Determine if the NYSE is currently open or closed
|
|
const currentHour = new Date(currentTime).getHours();
|
|
const isWeekend = new Date(currentTime).getDay() === 6 || new Date(currentTime).getDay() === 0;
|
|
const isBeforeMarketOpen = currentHour < 9 || (currentHour === 9 && new Date(currentTime).getMinutes() < 30);
|
|
const isAfterMarketClose = currentHour >= 16;
|
|
|
|
const isStockMarketOpen = !(isWeekend || isBeforeMarketOpen || isAfterMarketClose || holidays?.includes(currentDate));
|
|
let output;
|
|
if (isStockMarketOpen === true) {
|
|
|
|
const data = request.body;
|
|
const currentDate = new Date();
|
|
const year = currentDate.getFullYear();
|
|
const month = String(currentDate.getMonth() + 1).padStart(2, '0'); // Month is zero-based
|
|
const day = '01';
|
|
|
|
const formattedDate = `${year}-${month}-${day}`; // Output: "yyyy-mm-01"
|
|
|
|
const userId = data?.userId;
|
|
|
|
let newHolding = {'symbol': data['symbol'],
|
|
'name': data['name'],
|
|
'assetType': data['assetType'],
|
|
'numberOfShares': data['numberOfShares'],
|
|
'boughtPrice': data['boughtPrice'],
|
|
'currentPrice': data['boughtPrice'],
|
|
'dailyChange': 0,
|
|
'sinceBoughtChange': 0 }
|
|
|
|
let currentPortfolio = await pb.collection("portfolios").getList(1, 500, {
|
|
filter: `user="${userId}" && created >="${formattedDate}" `,
|
|
});
|
|
|
|
currentPortfolio = currentPortfolio?.items[0];
|
|
|
|
let holdings = currentPortfolio?.holdings || [];
|
|
|
|
let tradingHistory = currentPortfolio?.tradingHistory || [];
|
|
|
|
let availableCash = currentPortfolio?.availableCash - data['estimatedTotal'];
|
|
|
|
holdings.push(newHolding)
|
|
|
|
const updatedHoldings = processHoldingsList(holdings)
|
|
|
|
|
|
tradingHistory.push({'symbol': data['symbol'],
|
|
'name': data['name'],
|
|
'assetType': data['assetType'],
|
|
'numberOfShares': data['numberOfShares'],
|
|
'price': Number(data['boughtPrice']),
|
|
'type': 'buy',
|
|
'date': new Date()});
|
|
|
|
try {
|
|
|
|
await pb.collection("portfolios").update(currentPortfolio?.id, {
|
|
"holdings": updatedHoldings,
|
|
"availableCash": availableCash,
|
|
"tradingHistory": tradingHistory,
|
|
})
|
|
output = 'success';
|
|
|
|
} catch (err) {
|
|
output = 'failure'
|
|
}
|
|
}
|
|
else {
|
|
output = 'marketClosed'
|
|
}
|
|
|
|
reply.send({ items: output })
|
|
})
|
|
|
|
done();
|
|
};
|
|
|