UNPKG

@tomei/live-price

Version:

Tomei live-price Package

348 lines (327 loc) 12.7 kB
import { ClassError, ObjectBase } from '@tomei/general'; import { ITomeiPriceHistoryFindAllAttr, ITomeiPriceHistoryAttr, } from '../../interfaces/price-tomei-price-history-attr.interface'; import { TomeiPriceHistoryRepository } from './tomei-price.repository'; import { LoginUser } from '@tomei/sso'; import { Op, Sequelize } from 'sequelize'; import FeedHistoryModel from '../../models/price-feed-history.entity'; import { IFeedHistoryAttr } from '../../interfaces'; import { FeedManualPriceHistory } from '../feed-manual-price-history/feed-manual-price-history'; import { ManualPriceStatus, NonSourceFeedName } from '../../enum/feed.enum'; export class TomeiPriceHistory extends ObjectBase implements ITomeiPriceHistoryAttr { ObjectId: string; ObjectName: string; ObjectType: string; TableName: string; FeedHistoryId: string; FeedName: NonSourceFeedName; DateTime: Date; AdjustBuyPercentage: number; AdjustSellPercentage: number; TomeiBuyPrice: number; TomeiSellPrice: number; AdjustedById: string; Currency: string; AdjustedDateTime: Date; IsManualPriceActivatedYN: string; BuyLabourCharges: number; SellLabourCharges: number; get TomeiPriceHistoryId(): string { return this.ObjectId; } set TomeiPriceHistoryId(value: string) { this.ObjectId = value; } private static _Repo = new TomeiPriceHistoryRepository(); private constructor(tomeiPriceHistoryAttr?: ITomeiPriceHistoryAttr) { super(); if (tomeiPriceHistoryAttr) { this.TomeiPriceHistoryId = tomeiPriceHistoryAttr.TomeiPriceHistoryId; this.FeedHistoryId = tomeiPriceHistoryAttr.FeedHistoryId; this.FeedName = tomeiPriceHistoryAttr.FeedName; this.DateTime = tomeiPriceHistoryAttr.DateTime; this.AdjustBuyPercentage = tomeiPriceHistoryAttr.AdjustBuyPercentage; this.AdjustSellPercentage = tomeiPriceHistoryAttr.AdjustSellPercentage; this.TomeiBuyPrice = tomeiPriceHistoryAttr.TomeiBuyPrice; this.TomeiSellPrice = tomeiPriceHistoryAttr.TomeiSellPrice; this.AdjustedById = tomeiPriceHistoryAttr.AdjustedById; this.Currency = tomeiPriceHistoryAttr.Currency; this.AdjustedDateTime = tomeiPriceHistoryAttr.AdjustedDateTime; this.IsManualPriceActivatedYN = tomeiPriceHistoryAttr.IsManualPriceActivatedYN; this.BuyLabourCharges = tomeiPriceHistoryAttr.BuyLabourCharges; this.SellLabourCharges = tomeiPriceHistoryAttr.SellLabourCharges; } } public static async init( dbTransaction?: any, tomeiPriceHistoryId?: string, ): Promise<TomeiPriceHistory> { try { if (tomeiPriceHistoryId) { const data = await TomeiPriceHistory._Repo.findByPk( tomeiPriceHistoryId, dbTransaction, ); if (data) { return new TomeiPriceHistory(data); } else { throw new ClassError( 'TomeiPriceHistory', 'TomeiPriceHistoryErrMsg00', 'TomeiPriceHistory Not Found', ); } } return new TomeiPriceHistory(); } catch (error) { throw new ClassError( 'TomeiPriceHistory', 'TomeiPriceHistoryErrMsg00', 'TomeiPriceHistory To Initialize FeedHistory', ); } } public async saveTomeiPrice( feedName: NonSourceFeedName, //Tomei Price Feed Name not Price Feed Name feedHistory: IFeedHistoryAttr, loginUser?: LoginUser, adjustmentPercentage?: { adjustBuyPercentage: number; adjustSellPercentage: number; buyLabourCharges: number; sellLabourCharges: number; }, manualPrice?: { buyPrice: number; sellPrice: number; }, dbTransaction?: any, ): Promise<TomeiPriceHistory> { try { //Validate that feedHistoryId is not null if (!feedHistory || !feedHistory.FeedHistoryId) { throw new ClassError( 'TomeiPriceHistory', 'TomeiPriceHistoryErrMsg01', 'FeedHistoryId is required to create tomei price', ); } //Check if adjustmentPercentage is provided, if not retrieve the previous tomei price record for feedHistory.FeedName and feedHistory.Currency let adjustmentBy: string = null; let adjustmentDateTime: Date = new Date(); const latestPrice = await TomeiPriceHistory.getLatestPrice( feedName, feedHistory.Currency, undefined, dbTransaction, ); if (!adjustmentPercentage) { //If no previous tomei price record is found, set the adjustmentPercentage to 0 if (!latestPrice) { adjustmentPercentage = { adjustBuyPercentage: 0, adjustSellPercentage: 0, buyLabourCharges: 0, sellLabourCharges: 0, }; } else { adjustmentPercentage = { adjustBuyPercentage: latestPrice.AdjustBuyPercentage, adjustSellPercentage: latestPrice.AdjustSellPercentage, buyLabourCharges: latestPrice.BuyLabourCharges, sellLabourCharges: latestPrice.SellLabourCharges, }; adjustmentBy = latestPrice.AdjustedById; adjustmentDateTime = latestPrice.AdjustedDateTime; } } else if (!loginUser && adjustmentPercentage) { //If adjustmentPercentage is provided, validate that login user is provided if adjustmentPercentage is provided throw new ClassError( 'TomeiPriceHistory', 'TomeiPriceHistoryErrMsg01', 'Login user is required to create tomei price when updating adjustment buy and sell percentage', ); } //Check if manualPrice is provided, if provided, set the tomei buy and sell prices to the manual prices //If manualPrice is not provided, check if there is an active manual price record for the feedName //If there is an active manual price record, set the tomei buy and sell prices to the previous tomei price record //If there is no active manual price record, calculate the tomei buy and sell prices using the feedHistory prices and adjustment let tomeiBuyPrice: number; let tomeiSellPrice: number; let feedManualPrice = await FeedManualPriceHistory.findAll( 1, 1, { FeedName: feedName, Status: ManualPriceStatus.ACTIVE, }, dbTransaction, ); let IsManualPriceActivatedYN = 'N'; if (manualPrice) { tomeiBuyPrice = manualPrice.buyPrice; tomeiSellPrice = manualPrice.sellPrice; IsManualPriceActivatedYN = 'Y'; } else if (feedManualPrice.count > 0) { const manual = feedManualPrice.rows?.[0]; tomeiBuyPrice = manual?.BuyPrice ?? latestPrice?.TomeiBuyPrice ?? 0; tomeiSellPrice = manual?.SellPrice ?? latestPrice?.TomeiSellPrice ?? 0; IsManualPriceActivatedYN = 'Y'; } else { const weightMap: Record<NonSourceFeedName, number> = { [NonSourceFeedName.GOLD1000G]: 1000, [NonSourceFeedName.GOLD500G]: 500, [NonSourceFeedName.GOLD100G]: 100, [NonSourceFeedName.GOLD50G]: 50, [NonSourceFeedName.SILVER1000G]: 1000, [NonSourceFeedName.SILVER10OZ]: 311, }; let weight = weightMap[feedName] ?? 0; tomeiBuyPrice = feedHistory.FeedSellPrice * weight * (1 + adjustmentPercentage.adjustBuyPercentage / 100) + adjustmentPercentage.buyLabourCharges; tomeiSellPrice = feedHistory.FeedSellPrice * weight * (1 + adjustmentPercentage.adjustSellPercentage / 100) + adjustmentPercentage.sellLabourCharges; } const payload: ITomeiPriceHistoryAttr = { TomeiPriceHistoryId: this.createId(), FeedHistoryId: feedHistory.FeedHistoryId, FeedName: feedName, DateTime: new Date(), Currency: feedHistory.Currency, AdjustBuyPercentage: adjustmentPercentage.adjustBuyPercentage, AdjustSellPercentage: adjustmentPercentage.adjustSellPercentage, TomeiBuyPrice: tomeiBuyPrice, TomeiSellPrice: tomeiSellPrice, AdjustedById: loginUser ? loginUser.ObjectId : adjustmentBy, //If loginUser is provided, set the AdjustedById to loginUser AdjustedDateTime: adjustmentDateTime, IsManualPriceActivatedYN: IsManualPriceActivatedYN, BuyLabourCharges: adjustmentPercentage.buyLabourCharges, SellLabourCharges: adjustmentPercentage.sellLabourCharges, }; const tomeiPriceHistory = await TomeiPriceHistory._Repo.create(payload, { transaction: dbTransaction, }); if (tomeiPriceHistory) { return new TomeiPriceHistory(tomeiPriceHistory); } else { throw new ClassError( 'TomeiPriceHistory', 'TomeiPriceHistoryErrMsg01', 'TomeiPriceHistory To Save TomeiPrice', ); } } catch (error) { throw error; } } public static async getLatestPrice( feedName: NonSourceFeedName, currency: string, timestamp?: Date, dbTransaction?: any, ): Promise<ITomeiPriceHistoryAttr> { //The getLatestPrice() method retrieves price data from the price_FeedHistory table based on the provided feedname and currency . If a timestamp is provided, it retrieves the price record closest to that specific time. If no timestamp is provided, it uses the current timestamp to retrieve the price record. If no matching record is found, it returns an appropriate message. try { // Part 1: Define Query Filter // Create a query filter to search the price_FeedHistory table, ensuring the query includes: // The feedname. // The currency. const queryFilter: any = { FeedName: feedName, Currency: currency, }; const options: any = { where: queryFilter, order: [['DateTime', 'DESC']], limit: 1, transaction: dbTransaction, }; // If a timestamp is provided, find records closest to the timestamp. // If no timestamp is provided, use the current timestamp for the search. if (timestamp) { options.order = [ [ Sequelize.literal( `ABS(TIMESTAMPDIFF(SECOND, DateTime, '${timestamp.toISOString()}'))`, ), 'ASC', ], ]; } // Part 2: Search for Price Record // Use the query filter to retrieve the closest matching price record. // If timestamp is provided, adjust the filter to find the record closest to the provided timestamp. // If no timestamp is provided, use the current timestamp and return the most recent record before or equal to this time. const tomeiPrice = await TomeiPriceHistory._Repo.findOne(options); // Part 3: Handle Response // If a matching record is found, return the record. // If no matching record is found: // If searching with a timestamp, return the message: "No price record found for the specified timestamp." // If searching with the current timestamp, return the message: "No latest price record found for the current timestamp." if (tomeiPrice) { return tomeiPrice; } else { return null; } } catch (error) { throw error; } } public static async findAll( page: number, row: number, feedName: NonSourceFeedName, search?: { DateTime: { startDate: Date; endDate: Date; withManualHistory?: boolean; withCutOffHistory?: boolean; }; }, dbTransaction?: any, ): Promise<{ rows: ITomeiPriceHistoryFindAllAttr[]; count: number; }> { try { const queryObj: any = { FeedName: feedName, }; const options: any = { transaction: dbTransaction, limit: row, offset: row * (page - 1), order: [['DateTime', 'DESC']], include: [ { model: FeedHistoryModel, }, ], }; if (search) { queryObj.DateTime = { [Op.between]: [search.DateTime.startDate, search.DateTime.endDate], }; } return await TomeiPriceHistory._Repo.findAllWithPagination({ where: queryObj, ...options, }); } catch (error) { throw error; } } }