chore: strengthen backend eslint profile
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { CatalogDiscoveryService } from '../../application/catalog-discovery.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { formatDecimal } from '../../../../../common/decimal';
|
||||
|
||||
import type { TbankBond } from '../../../../../integrations/tbank/tbank.api';
|
||||
|
||||
import { formatDecimal } from '../../../../../common/decimal';
|
||||
import { decimal } from '../../../../../integrations/tbank/decimal';
|
||||
import { CatalogDiscoveryService } from '../../application/catalog-discovery.service';
|
||||
import { timestamp } from '../../application/instrument-market';
|
||||
import {
|
||||
BondDto,
|
||||
@@ -32,23 +34,24 @@ export class BondCatalogService {
|
||||
data:
|
||||
result.data?.map((item) => {
|
||||
const short = toBond(item);
|
||||
const detail = item.detail
|
||||
? toBond({ ...item.detail, uid: item.uid })
|
||||
: short;
|
||||
const detail = item.detail ?
|
||||
toBond({ ...item.detail, uid: item.uid }) :
|
||||
short;
|
||||
const last = item.price;
|
||||
return {
|
||||
...detail,
|
||||
classCode: detail.classCode ?? short.classCode,
|
||||
isin: detail.isin ?? short.isin,
|
||||
apiTradeAvailable: short.apiTradeAvailable,
|
||||
pricePercent: last?.price
|
||||
? formatDecimal(decimal(last.price))
|
||||
: null,
|
||||
pricePercent: last?.price ?
|
||||
formatDecimal(decimal(last.price)) :
|
||||
null,
|
||||
priceAt: timestamp(last?.time),
|
||||
};
|
||||
}) ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
async get(
|
||||
userId: string,
|
||||
uid: string,
|
||||
@@ -57,11 +60,12 @@ export class BondCatalogService {
|
||||
const result = await this.discovery.detail(userId, 'bond', uid, observe);
|
||||
return {
|
||||
...result,
|
||||
data: result.data
|
||||
? { ...toBond(result.data), slug: result.data.slug }
|
||||
: null,
|
||||
data: result.data ?
|
||||
{ ...toBond(result.data), slug: result.data.slug } :
|
||||
null,
|
||||
};
|
||||
}
|
||||
|
||||
async getByTicker(
|
||||
userId: string,
|
||||
ticker: string,
|
||||
@@ -75,9 +79,9 @@ export class BondCatalogService {
|
||||
);
|
||||
return {
|
||||
...result,
|
||||
data: result.data
|
||||
? { ...toBond(result.data), slug: result.data.slug }
|
||||
: null,
|
||||
data: result.data ?
|
||||
{ ...toBond(result.data), slug: result.data.slug } :
|
||||
null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
decimalFromString,
|
||||
divide,
|
||||
formatDecimal,
|
||||
multiply,
|
||||
divide,
|
||||
} from '../../../../../common/decimal';
|
||||
import {
|
||||
TbankAccessService,
|
||||
type TbankCoupon,
|
||||
type TbankBond,
|
||||
type TbankCoupon,
|
||||
} from '../../../../../integrations/tbank/tbank.api';
|
||||
import {
|
||||
PortfolioService,
|
||||
ForecastService,
|
||||
PortfolioService,
|
||||
} from '../../../portfolio/portfolio.api';
|
||||
import {
|
||||
CatalogEnrichmentService,
|
||||
@@ -20,14 +21,14 @@ import {
|
||||
} from '../../application/catalog-enrichment.service';
|
||||
import { moscowDay, timestamp } from '../../application/instrument-market';
|
||||
import { instrumentPosition } from '../../application/instrument-position';
|
||||
import { money } from '../infrastructure/bond-money.mapper';
|
||||
import {
|
||||
BondCouponsDto,
|
||||
BondCouponsResourceDto,
|
||||
BondPositionDto,
|
||||
BondMetricsDto,
|
||||
BondMetricsResourceDto,
|
||||
BondPositionDto,
|
||||
} from '../presentation/bond.dto';
|
||||
import { money } from '../infrastructure/bond-money.mapper';
|
||||
import { bondQuote } from './bond-market.service';
|
||||
const ISO_YEAR_LENGTH = 4;
|
||||
const INCOME_HISTORY_YEARS = 5;
|
||||
@@ -40,6 +41,7 @@ export class BondIncomeService {
|
||||
private readonly access: TbankAccessService,
|
||||
private readonly forecasts: ForecastService,
|
||||
) {}
|
||||
|
||||
async metrics(
|
||||
userId: string,
|
||||
uid: string,
|
||||
@@ -53,9 +55,9 @@ export class BondIncomeService {
|
||||
observe,
|
||||
);
|
||||
return {
|
||||
data: result.values.instrument
|
||||
? bondMetrics(result.values, result.unavailable, result.observedAt)
|
||||
: null,
|
||||
data: result.values.instrument ?
|
||||
bondMetrics(result.values, result.unavailable, result.observedAt) :
|
||||
null,
|
||||
meta: result.meta,
|
||||
};
|
||||
}
|
||||
@@ -67,6 +69,7 @@ export class BondIncomeService {
|
||||
meta: { ...saved.meta, resourceKey: `bond/position/${uid}` },
|
||||
};
|
||||
}
|
||||
|
||||
async coupons(
|
||||
userId: string,
|
||||
uid: string,
|
||||
@@ -85,21 +88,22 @@ export class BondIncomeService {
|
||||
['detail', 'coupons'],
|
||||
{ from, to },
|
||||
);
|
||||
if (sources[0].meta.availability === 'complete' && !sources[0].instrument)
|
||||
if (sources[0].meta.availability === 'complete' && !sources[0].instrument) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
const events = sources[1].payload?.coupons;
|
||||
const position = portfolio.data
|
||||
? instrumentPosition(portfolio.data, uid, 'BOND')
|
||||
: null;
|
||||
const projected = events
|
||||
? bondCoupons(
|
||||
const position = portfolio.data ?
|
||||
instrumentPosition(portfolio.data, uid, 'BOND') :
|
||||
null;
|
||||
const projected = events ?
|
||||
bondCoupons(
|
||||
events,
|
||||
position,
|
||||
{ from, to, today },
|
||||
sources[1].meta.lastSuccessfulAt ?? new Date().toISOString(),
|
||||
!portfolio.data,
|
||||
)
|
||||
: undefined;
|
||||
) :
|
||||
undefined;
|
||||
const result = await this.forecasts.result({
|
||||
userId,
|
||||
revision: connection.revision,
|
||||
@@ -110,9 +114,9 @@ export class BondIncomeService {
|
||||
candidate:
|
||||
portfolio.data && sources[0].instrument ? projected : undefined,
|
||||
});
|
||||
return result.data || !projected
|
||||
? result
|
||||
: {
|
||||
return result.data || !projected ?
|
||||
result :
|
||||
{
|
||||
data: bondCoupons(
|
||||
events ?? [],
|
||||
null,
|
||||
@@ -135,19 +139,19 @@ export function bondCoupons(
|
||||
const { from, to, today } = window;
|
||||
const quantity =
|
||||
position?.accounts.length &&
|
||||
position.accounts.every((p) => decimalFromString(p.quantity).value > 0n)
|
||||
? decimalFromString(position.quantity)
|
||||
: null;
|
||||
position.accounts.every((p) => decimalFromString(p.quantity).value > 0n) ?
|
||||
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 perBond = money(event.payOneBond);
|
||||
const timing = !paymentDate
|
||||
? ('undated' as const)
|
||||
: paymentDate >= today
|
||||
? ('upcoming' as const)
|
||||
: ('past' as const);
|
||||
const timing = !paymentDate ?
|
||||
('undated' as const) :
|
||||
paymentDate >= today ?
|
||||
('upcoming' as const) :
|
||||
('past' as const);
|
||||
return {
|
||||
number: event.couponNumber ?? null,
|
||||
paymentDate,
|
||||
@@ -161,14 +165,14 @@ export function bondCoupons(
|
||||
perBond &&
|
||||
timing === 'upcoming' &&
|
||||
recordDate &&
|
||||
recordDate >= today
|
||||
? {
|
||||
recordDate >= today ?
|
||||
{
|
||||
currency: perBond.currency,
|
||||
value: formatDecimal(
|
||||
multiply(quantity, decimalFromString(perBond.value)),
|
||||
),
|
||||
}
|
||||
: null,
|
||||
} :
|
||||
null,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => (a.paymentDate ?? '').localeCompare(b.paymentDate ?? ''));
|
||||
@@ -214,8 +218,8 @@ export function bondMetrics(
|
||||
clean &&
|
||||
coupon.currency === clean.currency &&
|
||||
decimalFromString(coupon.value).value >= 0n &&
|
||||
decimalFromString(clean.value).value > 0n
|
||||
? formatDecimal(
|
||||
decimalFromString(clean.value).value > 0n ?
|
||||
formatDecimal(
|
||||
divide(
|
||||
multiply(
|
||||
decimalFromString(coupon.value),
|
||||
@@ -227,14 +231,14 @@ export function bondMetrics(
|
||||
),
|
||||
COUPON_YIELD_DECIMAL_PLACES,
|
||||
),
|
||||
)
|
||||
: null;
|
||||
) :
|
||||
null;
|
||||
const couponType =
|
||||
next?.couponType && next.couponType !== 'COUPON_TYPE_UNSPECIFIED'
|
||||
? next.couponType
|
||||
: instrument.floatingCouponFlag === true
|
||||
? 'COUPON_TYPE_FLOATING'
|
||||
: null;
|
||||
next?.couponType && next.couponType !== 'COUPON_TYPE_UNSPECIFIED' ?
|
||||
next.couponType :
|
||||
instrument.floatingCouponFlag === true ?
|
||||
'COUPON_TYPE_FLOATING' :
|
||||
null;
|
||||
return {
|
||||
creditRating,
|
||||
coupon,
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { CandleService } from '../../application/candle.service';
|
||||
import type { TbankBond } from '../../../../../integrations/tbank/tbank.api';
|
||||
import {
|
||||
CatalogEnrichmentService,
|
||||
type CatalogPayload,
|
||||
} from '../../application/catalog-enrichment.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import type { TbankBond } from '../../../../../integrations/tbank/tbank.api';
|
||||
|
||||
import {
|
||||
add,
|
||||
decimalFromString,
|
||||
@@ -14,15 +11,19 @@ import {
|
||||
subtract,
|
||||
} from '../../../../../common/decimal';
|
||||
import { decimal } from '../../../../../integrations/tbank/decimal';
|
||||
import { CandleService } from '../../application/candle.service';
|
||||
import {
|
||||
CatalogEnrichmentService,
|
||||
type CatalogPayload,
|
||||
} from '../../application/catalog-enrichment.service';
|
||||
import { timestamp } from '../../application/instrument-market';
|
||||
import { money } from '../infrastructure/bond-money.mapper';
|
||||
import {
|
||||
BondCandlesQueryDto,
|
||||
BondQuoteDto,
|
||||
BondQuoteResourceDto,
|
||||
} from '../presentation/bond.dto';
|
||||
|
||||
import { money } from '../infrastructure/bond-money.mapper';
|
||||
|
||||
const PRICE_DECIMAL_PLACES = 9;
|
||||
@Injectable()
|
||||
export class BondMarketService {
|
||||
@@ -30,6 +31,7 @@ export class BondMarketService {
|
||||
private readonly history: CandleService,
|
||||
private readonly sources: CatalogEnrichmentService,
|
||||
) {}
|
||||
|
||||
async quote(
|
||||
userId: string,
|
||||
uid: string,
|
||||
@@ -43,12 +45,13 @@ export class BondMarketService {
|
||||
observe,
|
||||
);
|
||||
return {
|
||||
data: result.values.instrument
|
||||
? bondQuote(result.values, result.unavailable, result.observedAt)
|
||||
: null,
|
||||
data: result.values.instrument ?
|
||||
bondQuote(result.values, result.unavailable, result.observedAt) :
|
||||
null,
|
||||
meta: result.meta,
|
||||
};
|
||||
}
|
||||
|
||||
candles(
|
||||
userId: string,
|
||||
uid: string,
|
||||
@@ -77,8 +80,8 @@ export function bondQuote(
|
||||
const cleanPrice =
|
||||
pricePercent !== null &&
|
||||
nominal &&
|
||||
decimalFromString(nominal.value).value > 0n
|
||||
? {
|
||||
decimalFromString(nominal.value).value > 0n ?
|
||||
{
|
||||
currency: nominal.currency,
|
||||
value: formatDecimal(
|
||||
divide(
|
||||
@@ -90,11 +93,11 @@ export function bondQuote(
|
||||
PRICE_DECIMAL_PLACES,
|
||||
),
|
||||
),
|
||||
}
|
||||
: null;
|
||||
} :
|
||||
null;
|
||||
const dirtyPrice =
|
||||
cleanPrice && aci && aci.currency === cleanPrice.currency
|
||||
? {
|
||||
cleanPrice && aci && aci.currency === cleanPrice.currency ?
|
||||
{
|
||||
currency: cleanPrice.currency,
|
||||
value: formatDecimal(
|
||||
add(
|
||||
@@ -102,8 +105,8 @@ export function bondQuote(
|
||||
decimalFromString(aci.value),
|
||||
),
|
||||
),
|
||||
}
|
||||
: null;
|
||||
} :
|
||||
null;
|
||||
return {
|
||||
pricePercent,
|
||||
cleanPrice,
|
||||
@@ -112,9 +115,9 @@ export function bondQuote(
|
||||
priceAt,
|
||||
tradingStatus,
|
||||
changePercentagePoints:
|
||||
last?.price && previous?.close
|
||||
? formatDecimal(subtract(decimal(last.price), decimal(previous.close)))
|
||||
: null,
|
||||
last?.price && previous?.close ?
|
||||
formatDecimal(subtract(decimal(last.price), decimal(previous.close))) :
|
||||
null,
|
||||
previousCloseDate: timestamp(previous?.time)?.slice(0, 10) ?? null,
|
||||
unavailable,
|
||||
observedAt,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { PortfolioDto } from '../../../portfolio/portfolio.api';
|
||||
|
||||
import { instrumentPosition } from '../../application/instrument-position';
|
||||
import { bondCoupons, bondMetrics } from './bond-income.service';
|
||||
import { bondQuote } from './bond-market.service';
|
||||
import { instrumentPosition } from '../../application/instrument-position';
|
||||
import type { PortfolioDto } from '../../../portfolio/portfolio.api';
|
||||
jest.mock('../../../../../prisma/prisma.service', () => ({
|
||||
PrismaService: class {},
|
||||
}));
|
||||
@@ -122,9 +123,9 @@ describe('bond financial projections', () => {
|
||||
{
|
||||
couponDate: time('2026-10-10'),
|
||||
payOneBond:
|
||||
scenario === 'unknown'
|
||||
? undefined
|
||||
: money('30', scenario === 'currency' ? 'usd' : 'rub'),
|
||||
scenario === 'unknown' ?
|
||||
undefined :
|
||||
money('30', scenario === 'currency' ? 'usd' : 'rub'),
|
||||
couponPeriod: scenario === 'period' ? 0 : 90,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { formatDecimal } from '../../../../../common/decimal';
|
||||
import { type TbankMoney } from '../../../../../integrations/tbank/tbank.api';
|
||||
import { decimal } from '../../../../../integrations/tbank/decimal';
|
||||
import { type TbankMoney } from '../../../../../integrations/tbank/tbank.api';
|
||||
|
||||
export function money(value?: TbankMoney) {
|
||||
const currency = value?.currency?.toUpperCase();
|
||||
return value && currency
|
||||
? { currency, value: formatDecimal(decimal(value)) }
|
||||
: null;
|
||||
return value && currency ?
|
||||
{ currency, value: formatDecimal(decimal(value)) } :
|
||||
null;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { InvestmentReadQueryDto } from '../../../investment-resource.dto';
|
||||
import type { Request } from 'express';
|
||||
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
@@ -9,24 +10,25 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
|
||||
import { ApiProblemResponses } from '../../../../../common/decorators/api-safe-error-response.decorator';
|
||||
import { AccessPayload, JwtAuthGuard } from '../../../../auth/auth.api';
|
||||
import { InvestmentReadQueryDto } from '../../../investment-resource.dto';
|
||||
import { BondCatalogService } from '../application/bond-catalog.service';
|
||||
import { BondIncomeService } from '../application/bond-income.service';
|
||||
import { BondMarketService } from '../application/bond-market.service';
|
||||
import {
|
||||
BondCandlesResourceDto,
|
||||
BondCandlesQueryDto,
|
||||
BondCandlesResourceDto,
|
||||
BondCouponsResourceDto,
|
||||
BondResourceDto,
|
||||
BondMetricsResourceDto,
|
||||
BondPositionResourceDto,
|
||||
BondQuoteResourceDto,
|
||||
BondResourceDto,
|
||||
BondSearchQueryDto,
|
||||
BondSearchResourceDto,
|
||||
BondTickerParamsDto,
|
||||
} from './bond.dto';
|
||||
import { BondCatalogService } from '../application/bond-catalog.service';
|
||||
|
||||
@ApiTags('bonds')
|
||||
@ApiProblemResponses()
|
||||
@@ -39,6 +41,7 @@ export class BondController {
|
||||
private readonly market: BondMarketService,
|
||||
private readonly income: BondIncomeService,
|
||||
) {}
|
||||
|
||||
@Get(':uid/metrics')
|
||||
@ApiOkResponse({ type: BondMetricsResourceDto })
|
||||
metrics(
|
||||
@@ -48,6 +51,7 @@ export class BondController {
|
||||
) {
|
||||
return this.income.metrics(request.user.sub, uid, query.sync === 'observe');
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOkResponse({ type: BondSearchResourceDto })
|
||||
search(
|
||||
@@ -60,6 +64,7 @@ export class BondController {
|
||||
query.sync === 'observe',
|
||||
);
|
||||
}
|
||||
|
||||
@Get('by-ticker/:ticker')
|
||||
@ApiOkResponse({ type: BondResourceDto })
|
||||
getByTicker(
|
||||
@@ -73,6 +78,7 @@ export class BondController {
|
||||
query.sync === 'observe',
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':uid')
|
||||
@ApiOkResponse({ type: BondResourceDto })
|
||||
get(
|
||||
@@ -82,6 +88,7 @@ export class BondController {
|
||||
) {
|
||||
return this.bonds.get(request.user.sub, uid, query.sync === 'observe');
|
||||
}
|
||||
|
||||
@Get(':uid/quote')
|
||||
@ApiOkResponse({ type: BondQuoteResourceDto })
|
||||
quote(
|
||||
@@ -91,6 +98,7 @@ export class BondController {
|
||||
) {
|
||||
return this.market.quote(request.user.sub, uid, query.sync === 'observe');
|
||||
}
|
||||
|
||||
@Get(':uid/candles')
|
||||
@ApiOkResponse({ type: BondCandlesResourceDto })
|
||||
candles(
|
||||
@@ -105,6 +113,7 @@ export class BondController {
|
||||
query.sync === 'observe',
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':uid/position')
|
||||
@ApiOkResponse({ type: BondPositionResourceDto })
|
||||
position(
|
||||
@@ -118,6 +127,7 @@ export class BondController {
|
||||
query.sync === 'observe',
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':uid/coupons')
|
||||
@ApiOkResponse({ type: BondCouponsResourceDto })
|
||||
coupons(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { InvestmentResourceMetaDto } from '../../../investment-resource.dto';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { MoneyDto } from '../../../../../common/money.dto';
|
||||
|
||||
import { MoneyDto } from '../../../../../common/money.dto';
|
||||
import { InvestmentResourceMetaDto } from '../../../investment-resource.dto';
|
||||
import {
|
||||
StockCandlesDto,
|
||||
StockCandlesQueryDto,
|
||||
@@ -20,44 +20,61 @@ export class BondDto {
|
||||
description: 'Unambiguous ticker URL segment, or the exact instrument UID.',
|
||||
})
|
||||
declare slug: string;
|
||||
|
||||
@ApiProperty() declare name: string;
|
||||
@ApiProperty({ type: String, nullable: true }) declare isin: string | null;
|
||||
@ApiProperty({ type: String, nullable: true }) declare isin: null | string;
|
||||
@ApiProperty({ type: String, nullable: true }) declare classCode:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare realExchange:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: Boolean, nullable: true }) declare apiTradeAvailable:
|
||||
boolean | null;
|
||||
@ApiProperty({ type: String, nullable: true }) declare ticker: string | null;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare ticker: null | string;
|
||||
@ApiProperty({ type: String, nullable: true }) declare logoName:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare currency:
|
||||
string | null;
|
||||
@ApiProperty({ type: String, nullable: true }) declare sector: string | null;
|
||||
@ApiProperty({ type: Number, nullable: true }) declare lot: number | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare sector: null | string;
|
||||
@ApiProperty({ type: Number, nullable: true }) declare lot: null | number;
|
||||
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
||||
declare historyFrom: string | null;
|
||||
declare historyFrom: null | string;
|
||||
|
||||
@ApiProperty({ type: MoneyDto, nullable: true })
|
||||
declare nominal: MoneyDto | null;
|
||||
|
||||
@ApiProperty({ type: MoneyDto, nullable: true })
|
||||
declare initialNominal: MoneyDto | null;
|
||||
|
||||
@ApiProperty({ type: MoneyDto, nullable: true }) declare aci: MoneyDto | null;
|
||||
@ApiProperty({ type: String, nullable: true }) declare maturityDate:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare callDate:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare bondType:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare riskLevel:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: Number, nullable: true }) declare couponQuantityPerYear:
|
||||
number | null;
|
||||
null | number;
|
||||
|
||||
@ApiProperty({ type: Boolean, nullable: true }) declare floatingCoupon:
|
||||
boolean | null;
|
||||
|
||||
@ApiProperty({ type: Boolean, nullable: true }) declare perpetual:
|
||||
boolean | null;
|
||||
|
||||
@ApiProperty({ type: Boolean, nullable: true }) declare amortization:
|
||||
boolean | null;
|
||||
|
||||
@ApiProperty({ type: Boolean, nullable: true }) declare subordinated:
|
||||
boolean | null;
|
||||
}
|
||||
@@ -68,13 +85,15 @@ export class BondSearchResultDto extends BondDto {
|
||||
nullable: true,
|
||||
description: 'Clean price in percent of nominal, not money.',
|
||||
})
|
||||
declare pricePercent: string | null;
|
||||
declare pricePercent: null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
||||
declare priceAt: string | null;
|
||||
declare priceAt: null | string;
|
||||
}
|
||||
export class BondQuoteDto {
|
||||
@ApiProperty({ type: String, nullable: true }) declare pricePercent:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({
|
||||
type: MoneyDto,
|
||||
nullable: true,
|
||||
@@ -82,6 +101,7 @@ export class BondQuoteDto {
|
||||
'Indicative clean value at the current nominal; no FX conversion.',
|
||||
})
|
||||
declare cleanPrice: MoneyDto | null;
|
||||
|
||||
@ApiProperty({ type: MoneyDto, nullable: true }) declare aci: MoneyDto | null;
|
||||
@ApiProperty({
|
||||
type: MoneyDto,
|
||||
@@ -90,41 +110,53 @@ export class BondQuoteDto {
|
||||
'Indicative clean value plus current accrued interest, excluding fees.',
|
||||
})
|
||||
declare dirtyPrice: MoneyDto | null;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true })
|
||||
declare changePercentagePoints: string | null;
|
||||
declare changePercentagePoints: null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare previousCloseDate:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare tradingStatus:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
||||
declare priceAt: string | null;
|
||||
@ApiProperty({ type: [String] }) declare unavailable: string[];
|
||||
declare priceAt: null | string;
|
||||
|
||||
@ApiProperty({ type: String, isArray: true }) declare unavailable: string[];
|
||||
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
||||
}
|
||||
export class BondCouponDto {
|
||||
@ApiProperty({ type: String, nullable: true }) declare number: string | null;
|
||||
@ApiProperty({ type: String, nullable: true }) declare number: null | string;
|
||||
@ApiProperty({ type: String, nullable: true }) declare paymentDate:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare recordDate:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare couponType:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: Number, nullable: true }) declare periodDays:
|
||||
number | null;
|
||||
null | number;
|
||||
|
||||
@ApiProperty({ type: MoneyDto, nullable: true })
|
||||
declare perBond: MoneyDto | null;
|
||||
|
||||
@ApiProperty({ type: MoneyDto, nullable: true })
|
||||
declare estimatedAmount: MoneyDto | null;
|
||||
|
||||
@ApiProperty({ enum: ['upcoming', 'past', 'undated'] }) declare timing:
|
||||
'upcoming' | 'past' | 'undated';
|
||||
'past' | 'undated' | 'upcoming';
|
||||
}
|
||||
export class BondCouponsDto {
|
||||
@ApiProperty({ type: [BondCouponDto] }) declare coupons: BondCouponDto[];
|
||||
@ApiProperty({ type: BondCouponDto, isArray: true }) declare coupons: BondCouponDto[];
|
||||
@ApiProperty() declare from: string;
|
||||
@ApiProperty() declare to: string;
|
||||
@ApiProperty() declare observedAt: string;
|
||||
@ApiProperty({ type: String, nullable: true }) declare positionAt:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty() declare estimateUnavailable: boolean;
|
||||
@ApiProperty() declare positionIsStale: boolean;
|
||||
}
|
||||
@@ -132,6 +164,7 @@ export class BondCouponsDto {
|
||||
export class BondYieldDto {
|
||||
@ApiProperty({ description: 'MOEX effective annual yield in percent.' })
|
||||
declare value: string;
|
||||
|
||||
@ApiProperty() declare pricePercent: string;
|
||||
@ApiProperty({ format: 'date' }) declare date: string;
|
||||
@ApiProperty({
|
||||
@@ -139,14 +172,16 @@ export class BondYieldDto {
|
||||
nullable: true,
|
||||
description: 'MOEX yield target, e.g. MATDATE or OFFERDATE.',
|
||||
})
|
||||
declare dateType: string | null;
|
||||
declare dateType: null | string;
|
||||
|
||||
@ApiProperty({ format: 'date-time' }) declare tradeAt: string;
|
||||
}
|
||||
export class BondCreditRatingDto {
|
||||
@ApiProperty({ enum: ['NCR'] }) declare agency: 'NCR';
|
||||
@ApiProperty({ type: String, nullable: true }) declare value: string | null;
|
||||
@ApiProperty({ type: String, nullable: true }) declare value: null | string;
|
||||
@ApiProperty({ enum: ['active', 'withdrawn'] }) declare status:
|
||||
'active' | 'withdrawn';
|
||||
|
||||
@ApiProperty({ format: 'date' }) declare date: string;
|
||||
@ApiProperty({ format: 'uri' }) declare sourceUrl: string;
|
||||
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
||||
@@ -154,39 +189,50 @@ export class BondCreditRatingDto {
|
||||
export class BondMetricsDto {
|
||||
@ApiProperty({ type: BondCreditRatingDto, nullable: true })
|
||||
declare creditRating: BondCreditRatingDto | null;
|
||||
|
||||
@ApiProperty({ type: MoneyDto, nullable: true })
|
||||
declare coupon: MoneyDto | null;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true, format: 'date' })
|
||||
declare couponDate: string | null;
|
||||
declare couponDate: null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true }) declare couponType:
|
||||
string | null;
|
||||
null | string;
|
||||
|
||||
@ApiProperty({ type: Number, nullable: true }) declare couponPeriodDays:
|
||||
number | null;
|
||||
null | number;
|
||||
|
||||
@ApiProperty({
|
||||
type: String,
|
||||
nullable: true,
|
||||
description:
|
||||
'Next coupon × 365 / period days / indicative clean price × 100. Not yield to maturity.',
|
||||
})
|
||||
declare couponYieldPercent: string | null;
|
||||
declare couponYieldPercent: null | string;
|
||||
|
||||
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
||||
declare couponYieldPriceAt: string | null;
|
||||
declare couponYieldPriceAt: null | string;
|
||||
|
||||
@ApiProperty({ type: BondYieldDto, nullable: true })
|
||||
declare effectiveYield: BondYieldDto | null;
|
||||
@ApiProperty({ type: [String] }) declare unavailable: string[];
|
||||
|
||||
@ApiProperty({ type: String, isArray: true }) declare unavailable: string[];
|
||||
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
||||
}
|
||||
|
||||
export class BondPositionResourceDto {
|
||||
@ApiProperty({ type: BondPositionDto, nullable: true })
|
||||
declare data: BondPositionDto | null;
|
||||
|
||||
@ApiProperty({ type: InvestmentResourceMetaDto })
|
||||
declare meta: InvestmentResourceMetaDto;
|
||||
}
|
||||
|
||||
export class BondSearchResourceDto {
|
||||
// eslint-disable-next-line @darraghor/nestjs-typed/api-property-returning-array-should-set-array -- Nullable array union requires isArray in the explicit wire schema.
|
||||
@ApiProperty({ type: BondSearchResultDto, isArray: true, nullable: true })
|
||||
declare data: BondSearchResultDto[] | null;
|
||||
|
||||
@ApiProperty({ type: InvestmentResourceMetaDto })
|
||||
declare meta: InvestmentResourceMetaDto;
|
||||
}
|
||||
@@ -200,6 +246,7 @@ export class BondResourceDto {
|
||||
export class BondQuoteResourceDto {
|
||||
@ApiProperty({ type: BondQuoteDto, nullable: true })
|
||||
declare data: BondQuoteDto | null;
|
||||
|
||||
@ApiProperty({ type: InvestmentResourceMetaDto })
|
||||
declare meta: InvestmentResourceMetaDto;
|
||||
}
|
||||
@@ -207,6 +254,7 @@ export class BondQuoteResourceDto {
|
||||
export class BondMetricsResourceDto {
|
||||
@ApiProperty({ type: BondMetricsDto, nullable: true })
|
||||
declare data: BondMetricsDto | null;
|
||||
|
||||
@ApiProperty({ type: InvestmentResourceMetaDto })
|
||||
declare meta: InvestmentResourceMetaDto;
|
||||
}
|
||||
@@ -214,6 +262,7 @@ export class BondMetricsResourceDto {
|
||||
export class BondCandlesResourceDto {
|
||||
@ApiProperty({ type: BondCandlesDto, nullable: true })
|
||||
declare data: BondCandlesDto | null;
|
||||
|
||||
@ApiProperty({ type: InvestmentResourceMetaDto })
|
||||
declare meta: InvestmentResourceMetaDto;
|
||||
}
|
||||
@@ -221,6 +270,7 @@ export class BondCandlesResourceDto {
|
||||
export class BondCouponsResourceDto {
|
||||
@ApiProperty({ type: BondCouponsDto, nullable: true })
|
||||
declare data: BondCouponsDto | null;
|
||||
|
||||
@ApiProperty({ type: InvestmentResourceMetaDto })
|
||||
declare meta: InvestmentResourceMetaDto;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user