codex/frontend-infrastructure-tooling #39
@ -1,26 +1,32 @@
|
||||
import { Controller, Get, Param, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiOkResponse, ApiExtraModels } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../common/dto/api-response.dto';
|
||||
import { BondsService } from './bonds.service';
|
||||
import { BondEnvelopeDto, BondMarketDataEnvelopeDto, BondHistoryEnvelopeDto } from './dto/bonds-envelope.dto';
|
||||
|
||||
@ApiTags('Bonds')
|
||||
@ApiExtraModels(ApiResponseMeta)
|
||||
@Controller('securities/bonds')
|
||||
export class BondsController {
|
||||
constructor(private readonly bondsService: BondsService) {}
|
||||
|
||||
@Get(':secid')
|
||||
@ApiOperation({ summary: 'Получить спецификацию облигации' })
|
||||
@ApiOkResponse({ type: BondEnvelopeDto })
|
||||
async getBond(@Param('secid') secid: string) {
|
||||
return this.bondsService.getBond(secid);
|
||||
}
|
||||
|
||||
@Get(':secid/marketdata')
|
||||
@ApiOperation({ summary: 'Получить рыночные данные облигации' })
|
||||
@ApiOkResponse({ type: BondMarketDataEnvelopeDto })
|
||||
async getMarketData(@Param('secid') secid: string) {
|
||||
return this.bondsService.getMarketData(secid);
|
||||
}
|
||||
|
||||
@Get(':secid/history')
|
||||
@ApiOperation({ summary: 'Получить дневную историю торгов облигации' })
|
||||
@ApiOkResponse({ type: BondHistoryEnvelopeDto })
|
||||
async getHistory(
|
||||
@Param('secid') secid: string,
|
||||
@Query('from') from: string,
|
||||
|
||||
28
apps/backend/src/modules/bonds/dto/bonds-envelope.dto.ts
Normal file
28
apps/backend/src/modules/bonds/dto/bonds-envelope.dto.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../../common/dto/api-response.dto';
|
||||
import { BondMarketDataDto, BondResponseDto } from './bond-response.dto';
|
||||
import { BondHistoryItemDto } from './history-item.dto';
|
||||
|
||||
export class BondEnvelopeDto {
|
||||
@ApiProperty({ type: BondResponseDto })
|
||||
data!: BondResponseDto;
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
|
||||
export class BondMarketDataEnvelopeDto {
|
||||
@ApiProperty({ type: BondMarketDataDto })
|
||||
data!: BondMarketDataDto;
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
|
||||
export class BondHistoryEnvelopeDto {
|
||||
@ApiProperty({ type: [BondHistoryItemDto] })
|
||||
data!: BondHistoryItemDto[];
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
15
apps/backend/src/modules/bonds/dto/history-item.dto.ts
Normal file
15
apps/backend/src/modules/bonds/dto/history-item.dto.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class BondHistoryItemDto {
|
||||
@ApiProperty({ example: '2026-06-01' })
|
||||
date!: string;
|
||||
|
||||
@ApiProperty({ example: 100.45 })
|
||||
closePrice!: number;
|
||||
|
||||
@ApiPropertyOptional({ type: Number, nullable: true, example: 12.71 })
|
||||
yieldClose!: number | null;
|
||||
|
||||
@ApiPropertyOptional({ type: Number, nullable: true, example: 4.5 })
|
||||
duration!: number | null;
|
||||
}
|
||||
@ -1,15 +1,19 @@
|
||||
import { Controller, Get, Param, Query, ValidationPipe } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiOkResponse, ApiExtraModels } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../common/dto/api-response.dto';
|
||||
import { CandlesService } from './candles.service';
|
||||
import { CandlesQueryDto } from './dto/candles-query.dto';
|
||||
import { CandleEnvelopeDto } from './dto/candles-envelope.dto';
|
||||
|
||||
@ApiTags('Candles')
|
||||
@ApiExtraModels(ApiResponseMeta)
|
||||
@Controller('securities')
|
||||
export class CandlesController {
|
||||
constructor(private readonly candlesService: CandlesService) {}
|
||||
|
||||
@Get('shares/:secid/candles')
|
||||
@ApiOperation({ summary: 'Получить свечи акции' })
|
||||
@ApiOkResponse({ type: CandleEnvelopeDto })
|
||||
async getShareCandles(
|
||||
@Param('secid') secid: string,
|
||||
@Query(ValidationPipe) query: CandlesQueryDto,
|
||||
@ -19,6 +23,7 @@ export class CandlesController {
|
||||
|
||||
@Get('bonds/:secid/candles')
|
||||
@ApiOperation({ summary: 'Получить свечи облигации' })
|
||||
@ApiOkResponse({ type: CandleEnvelopeDto })
|
||||
async getBondCandles(
|
||||
@Param('secid') secid: string,
|
||||
@Query(ValidationPipe) query: CandlesQueryDto,
|
||||
|
||||
27
apps/backend/src/modules/candles/dto/candle-item.dto.ts
Normal file
27
apps/backend/src/modules/candles/dto/candle-item.dto.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CandleItemDto {
|
||||
@ApiProperty({ example: 321.3 })
|
||||
open!: number;
|
||||
|
||||
@ApiProperty({ example: 322.66 })
|
||||
high!: number;
|
||||
|
||||
@ApiProperty({ example: 321.2 })
|
||||
low!: number;
|
||||
|
||||
@ApiProperty({ example: 322.35 })
|
||||
close!: number;
|
||||
|
||||
@ApiProperty({ example: 1925163 })
|
||||
volume!: number;
|
||||
|
||||
@ApiProperty({ example: 620184479 })
|
||||
value!: number;
|
||||
|
||||
@ApiProperty({ example: '2026-06-01T10:00:00' })
|
||||
begin!: string;
|
||||
|
||||
@ApiProperty({ example: '2026-06-01T10:59:00' })
|
||||
end!: string;
|
||||
}
|
||||
11
apps/backend/src/modules/candles/dto/candles-envelope.dto.ts
Normal file
11
apps/backend/src/modules/candles/dto/candles-envelope.dto.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../../common/dto/api-response.dto';
|
||||
import { CandleItemDto } from './candle-item.dto';
|
||||
|
||||
export class CandleEnvelopeDto {
|
||||
@ApiProperty({ type: [CandleItemDto] })
|
||||
data!: CandleItemDto[];
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
11
apps/backend/src/modules/health/dto/health-envelope.dto.ts
Normal file
11
apps/backend/src/modules/health/dto/health-envelope.dto.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../../common/dto/api-response.dto';
|
||||
import { HealthResponseDto } from './health-response.dto';
|
||||
|
||||
export class HealthEnvelopeDto {
|
||||
@ApiProperty({ type: HealthResponseDto })
|
||||
data!: HealthResponseDto;
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
12
apps/backend/src/modules/health/dto/health-response.dto.ts
Normal file
12
apps/backend/src/modules/health/dto/health-response.dto.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class HealthResponseDto {
|
||||
@ApiProperty({ example: 'ok' })
|
||||
status!: string;
|
||||
|
||||
@ApiProperty({ example: '2026-06-23T06:00:00.000Z' })
|
||||
timestamp!: string;
|
||||
|
||||
@ApiProperty({ example: 12345 })
|
||||
uptime!: number;
|
||||
}
|
||||
@ -1,13 +1,17 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiOkResponse, ApiExtraModels } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../common/dto/api-response.dto';
|
||||
import { Public } from '../auth/decorators/public.decorator';
|
||||
import { HealthEnvelopeDto } from './dto/health-envelope.dto';
|
||||
|
||||
@ApiTags('Health')
|
||||
@ApiExtraModels(ApiResponseMeta)
|
||||
@Controller('health')
|
||||
export class HealthController {
|
||||
@Get()
|
||||
@Public()
|
||||
@ApiOperation({ summary: 'Проверка состояния сервиса' })
|
||||
@ApiOkResponse({ type: HealthEnvelopeDto })
|
||||
check() {
|
||||
return {
|
||||
status: 'ok',
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../../common/dto/api-response.dto';
|
||||
|
||||
export class SearchResultItemDto {
|
||||
@ApiProperty({ example: 'SBER' })
|
||||
secid!: string;
|
||||
|
||||
@ApiProperty({ example: 'RU0009029540' })
|
||||
isin!: string;
|
||||
|
||||
@ApiProperty({ example: 'Сбербанк' })
|
||||
shortName!: string;
|
||||
|
||||
@ApiProperty({ enum: ['share', 'bond'] })
|
||||
type!: 'share' | 'bond';
|
||||
|
||||
@ApiProperty({ example: 1 })
|
||||
listLevel!: number;
|
||||
|
||||
@ApiPropertyOptional({ type: String, nullable: true, example: 'RUB' })
|
||||
currency!: string | null;
|
||||
|
||||
@ApiPropertyOptional({ type: Number, nullable: true, example: 322.35 })
|
||||
price!: number | null;
|
||||
}
|
||||
|
||||
export class SearchEnvelopeDto {
|
||||
@ApiProperty({ type: [SearchResultItemDto] })
|
||||
data!: SearchResultItemDto[];
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
@ -1,12 +1,15 @@
|
||||
import { Controller, Get, Query, ValidationPipe } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiOkResponse } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiOkResponse, ApiExtraModels } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../common/dto/api-response.dto';
|
||||
import { SecuritiesService } from './securities.service';
|
||||
import { ScreenerService } from './screener.service';
|
||||
import { SearchQueryDto, SecurityType } from './dto/search-query.dto';
|
||||
import { ScreenerQueryDto } from './dto/screener-query.dto';
|
||||
import { ScreenerResponseDto } from './dto/screener-response.dto';
|
||||
import { SearchEnvelopeDto } from './dto/search-response.dto';
|
||||
|
||||
@ApiTags('Securities')
|
||||
@ApiExtraModels(ApiResponseMeta)
|
||||
@Controller('securities')
|
||||
export class SecuritiesController {
|
||||
constructor(
|
||||
@ -16,6 +19,7 @@ export class SecuritiesController {
|
||||
|
||||
@Get('search')
|
||||
@ApiOperation({ summary: 'Поиск по инструментам' })
|
||||
@ApiOkResponse({ type: SearchEnvelopeDto })
|
||||
async search(@Query(ValidationPipe) query: SearchQueryDto) {
|
||||
const results = await this.securitiesService.search(
|
||||
query.q,
|
||||
|
||||
12
apps/backend/src/modules/shares/dto/dividend-item.dto.ts
Normal file
12
apps/backend/src/modules/shares/dto/dividend-item.dto.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class DividendItemDto {
|
||||
@ApiProperty({ example: '2026-05-15' })
|
||||
registryCloseDate!: string;
|
||||
|
||||
@ApiProperty({ example: 33.47 })
|
||||
value!: number;
|
||||
|
||||
@ApiProperty({ example: 'RUB' })
|
||||
currency!: string;
|
||||
}
|
||||
24
apps/backend/src/modules/shares/dto/history-item.dto.ts
Normal file
24
apps/backend/src/modules/shares/dto/history-item.dto.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class HistoryItemDto {
|
||||
@ApiProperty({ example: '2026-06-01' })
|
||||
date!: string;
|
||||
|
||||
@ApiProperty({ example: 321.3 })
|
||||
open!: number;
|
||||
|
||||
@ApiProperty({ example: 322.66 })
|
||||
high!: number;
|
||||
|
||||
@ApiProperty({ example: 321.2 })
|
||||
low!: number;
|
||||
|
||||
@ApiProperty({ example: 322.35 })
|
||||
close!: number;
|
||||
|
||||
@ApiProperty({ example: 1925163 })
|
||||
volume!: number;
|
||||
|
||||
@ApiProperty({ example: 620184479 })
|
||||
value!: number;
|
||||
}
|
||||
38
apps/backend/src/modules/shares/dto/shares-envelope.dto.ts
Normal file
38
apps/backend/src/modules/shares/dto/shares-envelope.dto.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../../common/dto/api-response.dto';
|
||||
import { ShareResponseDto } from './share-response.dto';
|
||||
import { ShareMarketDataResponseDto } from './share-marketdata-response.dto';
|
||||
import { HistoryItemDto } from './history-item.dto';
|
||||
import { DividendItemDto } from './dividend-item.dto';
|
||||
|
||||
export class ShareEnvelopeDto {
|
||||
@ApiProperty({ type: ShareResponseDto })
|
||||
data!: ShareResponseDto;
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
|
||||
export class ShareMarketDataEnvelopeDto {
|
||||
@ApiProperty({ type: ShareMarketDataResponseDto })
|
||||
data!: ShareMarketDataResponseDto;
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
|
||||
export class DividendsEnvelopeDto {
|
||||
@ApiProperty({ type: [DividendItemDto] })
|
||||
data!: DividendItemDto[];
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
|
||||
export class ShareHistoryEnvelopeDto {
|
||||
@ApiProperty({ type: [HistoryItemDto] })
|
||||
data!: HistoryItemDto[];
|
||||
|
||||
@ApiProperty({ type: ApiResponseMeta })
|
||||
meta!: ApiResponseMeta;
|
||||
}
|
||||
@ -1,14 +1,23 @@
|
||||
import { Controller, Get, Param, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiOkResponse, ApiExtraModels } from '@nestjs/swagger';
|
||||
import { ApiResponseMeta } from '../../common/dto/api-response.dto';
|
||||
import { SharesService } from './shares.service';
|
||||
import {
|
||||
ShareEnvelopeDto,
|
||||
ShareMarketDataEnvelopeDto,
|
||||
DividendsEnvelopeDto,
|
||||
ShareHistoryEnvelopeDto,
|
||||
} from './dto/shares-envelope.dto';
|
||||
|
||||
@ApiTags('Shares')
|
||||
@ApiExtraModels(ApiResponseMeta)
|
||||
@Controller('securities/shares')
|
||||
export class SharesController {
|
||||
constructor(private readonly sharesService: SharesService) {}
|
||||
|
||||
@Get(':secid')
|
||||
@ApiOperation({ summary: 'Получить спецификацию акции' })
|
||||
@ApiOkResponse({ type: ShareEnvelopeDto })
|
||||
async getShare(@Param('secid') secid: string) {
|
||||
const share = await this.sharesService.getShare(secid);
|
||||
return { data: share, meta: { cachedAt: null, fromCache: false } };
|
||||
@ -16,18 +25,21 @@ export class SharesController {
|
||||
|
||||
@Get(':secid/marketdata')
|
||||
@ApiOperation({ summary: 'Получить рыночные данные акции' })
|
||||
@ApiOkResponse({ type: ShareMarketDataEnvelopeDto })
|
||||
async getMarketData(@Param('secid') secid: string) {
|
||||
return this.sharesService.getMarketData(secid);
|
||||
}
|
||||
|
||||
@Get(':secid/dividends')
|
||||
@ApiOperation({ summary: 'Получить дивиденды' })
|
||||
@ApiOkResponse({ type: DividendsEnvelopeDto })
|
||||
async getDividends(@Param('secid') secid: string) {
|
||||
return this.sharesService.getDividends(secid);
|
||||
}
|
||||
|
||||
@Get(':secid/history')
|
||||
@ApiOperation({ summary: 'Получить дневную историю торгов акции' })
|
||||
@ApiOkResponse({ type: ShareHistoryEnvelopeDto })
|
||||
async getHistory(
|
||||
@Param('secid') secid: string,
|
||||
@Query('from') from: string,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user