refactor: replace ignored numeric literals with constants
This commit is contained in:
@@ -14,8 +14,11 @@ import {
|
||||
|
||||
type IdentifiedBond = TbankBond & { uid: string };
|
||||
|
||||
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
|
||||
import { money } from '../infrastructure/bond-money.mapper';
|
||||
|
||||
const MIN_LOT_EXCLUSIVE = 0;
|
||||
|
||||
@Injectable()
|
||||
export class BondCatalogService {
|
||||
constructor(private readonly discovery: CatalogDiscoveryService) {}
|
||||
@@ -100,13 +103,13 @@ function toBond(bond: IdentifiedBond): BondDto {
|
||||
currency: bond.currency?.toUpperCase() || null,
|
||||
bondType: bond.bondType || null,
|
||||
sector: bond.sector || null,
|
||||
lot: bond.lot && bond.lot > 0 ? bond.lot : null,
|
||||
lot: bond.lot && bond.lot > MIN_LOT_EXCLUSIVE ? bond.lot : null,
|
||||
historyFrom: timestamp(bond.first_1dayCandleDate),
|
||||
nominal: money(bond.nominal),
|
||||
initialNominal: money(bond.initialNominal),
|
||||
aci: money(bond.aciValue),
|
||||
maturityDate: timestamp(bond.maturityDate)?.slice(0, 10) ?? null,
|
||||
callDate: timestamp(bond.callDate)?.slice(0, 10) ?? null,
|
||||
maturityDate: timestamp(bond.maturityDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null,
|
||||
callDate: timestamp(bond.callDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null,
|
||||
couponQuantityPerYear: bond.couponQuantityPerYear ?? null,
|
||||
floatingCoupon: bond.floatingCouponFlag ?? null,
|
||||
perpetual: bond.perpetualFlag ?? null,
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
formatDecimal,
|
||||
multiply,
|
||||
} from '../../../../../common/decimal';
|
||||
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
|
||||
import {
|
||||
TbankAccessService,
|
||||
type TbankBond,
|
||||
@@ -30,6 +31,12 @@ import {
|
||||
BondPositionDto,
|
||||
} from '../presentation/bond.dto';
|
||||
import { bondQuote } from './bond-market.service';
|
||||
|
||||
const INCOME_FORECAST_YEARS = 1;
|
||||
const ZERO_QUANTITY = 0n;
|
||||
const MIN_COUPON_PERIOD_EXCLUSIVE = 0;
|
||||
const ZERO_AMOUNT = 0n;
|
||||
|
||||
const ISO_YEAR_LENGTH = 4;
|
||||
const INCOME_HISTORY_YEARS = 5;
|
||||
const COUPON_YIELD_DECIMAL_PLACES = 4;
|
||||
@@ -77,8 +84,8 @@ export class BondIncomeService {
|
||||
): Promise<BondCouponsResourceDto> {
|
||||
const connection = await this.access.local(userId);
|
||||
const today = moscowDay(new Date().toISOString());
|
||||
const from = `${Number(today.slice(0, ISO_YEAR_LENGTH)) - INCOME_HISTORY_YEARS}${today.slice(ISO_YEAR_LENGTH)}`;
|
||||
const to = `${Number(today.slice(0, ISO_YEAR_LENGTH)) + 1}${today.slice(ISO_YEAR_LENGTH)}`;
|
||||
const from = `${Number(today.slice(ISO_DATE_START, ISO_YEAR_LENGTH)) - INCOME_HISTORY_YEARS}${today.slice(ISO_YEAR_LENGTH)}`;
|
||||
const to = `${Number(today.slice(ISO_DATE_START, ISO_YEAR_LENGTH)) + INCOME_FORECAST_YEARS}${today.slice(ISO_YEAR_LENGTH)}`;
|
||||
const portfolio = await this.portfolios.read(userId, 'all', observe);
|
||||
const sources = await this.sources.readMany(
|
||||
userId,
|
||||
@@ -139,13 +146,13 @@ export function bondCoupons(
|
||||
const { from, to, today } = window;
|
||||
const quantity =
|
||||
position?.accounts.length &&
|
||||
position.accounts.every((p) => decimalFromString(p.quantity).value > 0n) ?
|
||||
position.accounts.every((p) => decimalFromString(p.quantity).value > ZERO_QUANTITY) ?
|
||||
decimalFromString(position.quantity) :
|
||||
null;
|
||||
const coupons = events
|
||||
.map((event) => {
|
||||
const paymentDate = timestamp(event.couponDate)?.slice(0, 10) ?? null;
|
||||
const recordDate = timestamp(event.fixDate)?.slice(0, 10) ?? null;
|
||||
const paymentDate = timestamp(event.couponDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null;
|
||||
const recordDate = timestamp(event.fixDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null;
|
||||
const perBond = money(event.payOneBond);
|
||||
const timing = !paymentDate ?
|
||||
('undated' as const) :
|
||||
@@ -198,10 +205,10 @@ export function bondMetrics(
|
||||
const effectiveYield = values.effectiveYield ?? null;
|
||||
const creditRating = values.creditRating ?? null;
|
||||
const today = moscowDay(new Date().toISOString());
|
||||
const to = `${Number(today.slice(0, ISO_YEAR_LENGTH)) + 1}${today.slice(ISO_YEAR_LENGTH)}`;
|
||||
const to = `${Number(today.slice(ISO_DATE_START, ISO_YEAR_LENGTH)) + INCOME_FORECAST_YEARS}${today.slice(ISO_YEAR_LENGTH)}`;
|
||||
const next = events
|
||||
?.filter((event) => {
|
||||
const date = timestamp(event.couponDate)?.slice(0, 10);
|
||||
const date = timestamp(event.couponDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH);
|
||||
return date && date >= today && date <= to;
|
||||
})
|
||||
.sort(
|
||||
@@ -210,15 +217,15 @@ export function bondMetrics(
|
||||
const coupon = money(next?.payOneBond);
|
||||
const period = next?.couponPeriod;
|
||||
const couponPeriodDays =
|
||||
period && Number.isInteger(period) && period > 0 ? period : null;
|
||||
period && Number.isInteger(period) && period > MIN_COUPON_PERIOD_EXCLUSIVE ? period : null;
|
||||
const clean = quote?.cleanPrice;
|
||||
const couponYieldPercent =
|
||||
coupon &&
|
||||
couponPeriodDays &&
|
||||
clean &&
|
||||
coupon.currency === clean.currency &&
|
||||
decimalFromString(coupon.value).value >= 0n &&
|
||||
decimalFromString(clean.value).value > 0n ?
|
||||
decimalFromString(coupon.value).value >= ZERO_AMOUNT &&
|
||||
decimalFromString(clean.value).value > ZERO_AMOUNT ?
|
||||
formatDecimal(
|
||||
divide(
|
||||
multiply(
|
||||
@@ -242,7 +249,7 @@ export function bondMetrics(
|
||||
return {
|
||||
creditRating,
|
||||
coupon,
|
||||
couponDate: timestamp(next?.couponDate)?.slice(0, 10) ?? null,
|
||||
couponDate: timestamp(next?.couponDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null,
|
||||
couponType,
|
||||
couponPeriodDays,
|
||||
couponYieldPercent,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
multiply,
|
||||
subtract,
|
||||
} from '../../../../../common/decimal';
|
||||
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
|
||||
import { decimal } from '../../../../../integrations/tbank/decimal';
|
||||
import { CandleService } from '../../application/candle.service';
|
||||
import {
|
||||
@@ -24,6 +25,8 @@ import {
|
||||
BondQuoteResourceDto,
|
||||
} from '../presentation/bond.dto';
|
||||
|
||||
const ZERO_AMOUNT = 0n;
|
||||
|
||||
const PRICE_DECIMAL_PLACES = 9;
|
||||
@Injectable()
|
||||
export class BondMarketService {
|
||||
@@ -80,7 +83,7 @@ export function bondQuote(
|
||||
const cleanPrice =
|
||||
pricePercent !== null &&
|
||||
nominal &&
|
||||
decimalFromString(nominal.value).value > 0n ?
|
||||
decimalFromString(nominal.value).value > ZERO_AMOUNT ?
|
||||
{
|
||||
currency: nominal.currency,
|
||||
value: formatDecimal(
|
||||
@@ -118,7 +121,7 @@ export function bondQuote(
|
||||
last?.price && previous?.close ?
|
||||
formatDecimal(subtract(decimal(last.price), decimal(previous.close))) :
|
||||
null,
|
||||
previousCloseDate: timestamp(previous?.time)?.slice(0, 10) ?? null,
|
||||
previousCloseDate: timestamp(previous?.time)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null,
|
||||
unavailable,
|
||||
observedAt,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user