diff --git a/server/schemes/ZanoPrice.ts b/server/schemes/ZanoPrice.ts index f6c348f..357b971 100644 --- a/server/schemes/ZanoPrice.ts +++ b/server/schemes/ZanoPrice.ts @@ -3,8 +3,8 @@ import sequelize from "../database/sequelize"; class ZanoPrice extends Model { declare readonly id: number; - declare ts_utc: string; - declare price_close: string; + declare timestamp: string; + declare price: string; declare src: string; declare raw: object; @@ -20,18 +20,18 @@ export type IZanoPrice = Omit< ZanoPrice.init( { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, - ts_utc: { - type: DataTypes.STRING, + timestamp: { + type: DataTypes.BIGINT, allowNull: false, unique: true }, - price_close: { type: DataTypes.DECIMAL(20, 10), allowNull: false }, + price: { type: DataTypes.DECIMAL(20, 10), allowNull: false }, src: { type: DataTypes.STRING, allowNull: false, defaultValue: "mexc" }, raw: { type: DataTypes.JSONB, allowNull: false }, }, { sequelize, - modelName: "zano_price", + modelName: "zano_price_data", timestamps: true, } ); diff --git a/server/server.ts b/server/server.ts index 3a50146..7453191 100644 --- a/server/server.ts +++ b/server/server.ts @@ -68,7 +68,8 @@ async function waitForDb() { (async () => { await waitForDb(); - await syncLatestPrice().then(() => syncHistoricalPrice()); + await syncLatestPrice(); + syncHistoricalPrice(); // async io.engine.on('initial_headers', (headers, req) => { headers['Access-Control-Allow-Origin'] = config.frontend_api @@ -267,34 +268,38 @@ async function waitForDb() { app.get( "/api/get_historical_zano_price", exceptionHandler(async (req, res) => { - let whereClause: any = {}; - if (req.query.from || req.query.to) { - const from = req.query.from - ? isNaN(Number(req.query.from)) - ? Date.parse(String(req.query.from)) - : Number(req.query.from) - : 0; + const target_timestamp = req.query.timestamp ? parseInt(req?.query?.timestamp as string) : null; - const to = req.query.to - ? isNaN(Number(req.query.to)) - ? Date.parse(String(req.query.to)) - : Number(req.query.to) - : Date.now(); - - whereClause = { - ts_utc: { - [Op.between]: [Number(from), Number(to)], - }, - }; + if (!target_timestamp) { + return res.json({ + success: false, + data: 'invalid timestamp' + }) } - const prices = await ZanoPrice.findAll({ - where: whereClause, - order: [["ts_utc", "ASC"]], + const closestPrice = await ZanoPrice.findOne({ + order: [[Sequelize.literal('ABS(timestamp - $targetTs)'), 'ASC']], + bind: { targetTs: target_timestamp }, + raw: true, }); - res.json(prices); + if (!closestPrice) { + return res.json({ + success: false, + data: 'price not found (unexpected error)' + }); + } + + res.json({ + success: true, + data: { + timestamp: closestPrice.timestamp, + price: closestPrice.price, + src: closestPrice.src, + raw: closestPrice.raw + } + }); }) ); diff --git a/server/services/zanoPrice.service.ts b/server/services/zanoPrice.service.ts index 602b6cb..a4d82c0 100644 --- a/server/services/zanoPrice.service.ts +++ b/server/services/zanoPrice.service.ts @@ -6,38 +6,36 @@ const BASE_URL = `https://api.mexc.com/api/v3/klines?symbol=ZANOUSDT&interval=1m const HISTORY_LIMIT_MS = 365 * 24 * 60 * 60 * 1000; // 1 year async function fetchPriceForTimestamp(timestamp: number) { - console.log(`Fetching price for timestamp: ${timestamp}`); const url = `${BASE_URL}&startTime=${timestamp}`; const res = await axios.get(url); if (!Array.isArray(res.data) || res.data.length === 0) return null; return { - ts_utc: timestamp, - price_close: String(res.data[0][4]), + timestamp: timestamp, + price: String(res.data[0][4]), raw: res.data[0], }; } export async function syncHistoricalPrice() { const oldestPrice = await ZanoPrice.findOne({ - order: [["ts_utc", "ASC"]], + order: [["timestamp", "ASC"]], raw: true, }); - console.log(oldestPrice); if (!oldestPrice) { throw new Error("Sync latest price before historical"); } - if (parseInt(oldestPrice.ts_utc, 10) < (+new Date() - HISTORY_LIMIT_MS)) { + if (parseInt(oldestPrice.timestamp, 10) < (+new Date() - HISTORY_LIMIT_MS)) { return console.log(`[zano price] Historical Price already synced`); } const timestampsToSync: number[] = []; - let oldestTimestamp = parseInt(oldestPrice.ts_utc, 10); + let oldestTimestamp = parseInt(oldestPrice.timestamp, 10); while (oldestTimestamp > (+new Date() - HISTORY_LIMIT_MS)) { oldestTimestamp -= FOUR_HOURS_MS; @@ -63,14 +61,14 @@ export async function syncHistoricalPrice() { export async function syncLatestPrice() { const lastRow = await ZanoPrice.findOne({ - attributes: ["ts_utc"], - order: [["ts_utc", "DESC"]], + attributes: ["timestamp"], + order: [["timestamp", "DESC"]], raw: true, }); - if (lastRow?.ts_utc && parseInt(lastRow.ts_utc, 10) > (+new Date() - FOUR_HOURS_MS)) { + if (lastRow?.timestamp && parseInt(lastRow.timestamp, 10) > (+new Date() - FOUR_HOURS_MS)) { return console.log( - `[zano price] Nothing to sync since ${new Date(parseInt(lastRow.ts_utc, 10)).toUTCString()} (UTC)` + `[zano price] Nothing to sync since ${new Date(parseInt(lastRow.timestamp, 10)).toUTCString()} (UTC)` ); } const latestPrice = await fetchPriceForTimestamp(+new Date());