Backend security / security (push) Successful in 8s
Backend verify / verify (push) Failing after 10m45s
Conventional commits / commits (pull_request) Successful in 29s
Backend security / security (pull_request) Successful in 8s
Backend verify / verify (pull_request) Failing after 10m37s
Store account membership, portfolio, operations, forecasts and market sources in SQLite. Coalesce scoped refreshes, fence connection revisions, preserve complete financial snapshots and stabilize operation period state. BREAKING CHANGE: investment reads return data/meta resource envelopes and locally persisted snapshots; consumers must use the matching OpenAPI contract and explicit synchronization endpoints.
224 lines
8.4 KiB
TypeScript
224 lines
8.4 KiB
TypeScript
import {
|
|
InvestmentReadQueryDto,
|
|
InvestmentResourceMetaDto,
|
|
} from '../../../investment-resource.dto';
|
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
import { Transform } from 'class-transformer';
|
|
import {
|
|
IsIn,
|
|
IsOptional,
|
|
IsString,
|
|
Matches,
|
|
MaxLength,
|
|
MinLength,
|
|
} from 'class-validator';
|
|
import { MoneyDto } from '../../../../../common/money.dto';
|
|
import { PortfolioPositionDto } from '../../../portfolio/portfolio.api';
|
|
|
|
const MAX_INSTRUMENT_QUERY_LENGTH = 80;
|
|
|
|
export class StockSearchQueryDto extends InvestmentReadQueryDto {
|
|
@ApiProperty({ minLength: 2, maxLength: MAX_INSTRUMENT_QUERY_LENGTH })
|
|
@Transform(({ value }: { value: unknown }) =>
|
|
typeof value === 'string' ? value.trim() : value,
|
|
)
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(MAX_INSTRUMENT_QUERY_LENGTH)
|
|
declare query: string;
|
|
}
|
|
export class StockTickerParamsDto {
|
|
@ApiProperty({
|
|
minLength: 1,
|
|
maxLength: MAX_INSTRUMENT_QUERY_LENGTH,
|
|
pattern: '^[A-Za-z0-9][A-Za-z0-9._@+-]*$',
|
|
})
|
|
@IsString()
|
|
@MinLength(1)
|
|
@MaxLength(MAX_INSTRUMENT_QUERY_LENGTH)
|
|
@Matches(/^[A-Za-z0-9][A-Za-z0-9._@+-]*$/)
|
|
declare ticker: string;
|
|
}
|
|
export class StockCandlesQueryDto extends InvestmentReadQueryDto {
|
|
@ApiPropertyOptional({
|
|
enum: ['month', 'halfYear', 'year', 'all'],
|
|
default: 'month',
|
|
})
|
|
@IsOptional()
|
|
@IsIn(['month', 'halfYear', 'year', 'all'])
|
|
period?: 'month' | 'halfYear' | 'year' | 'all';
|
|
}
|
|
export class StockDto {
|
|
@ApiProperty({ format: 'uuid' }) declare instrumentUid: string;
|
|
@ApiProperty({
|
|
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 classCode:
|
|
string | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare realExchange:
|
|
string | null;
|
|
@ApiProperty({ type: Boolean, nullable: true }) declare apiTradeAvailable:
|
|
boolean | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare ticker: string | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare logoName:
|
|
string | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare currency:
|
|
string | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare shareType:
|
|
string | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare sector: string | null;
|
|
@ApiProperty({ type: Number, nullable: true }) declare lot: number | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
|
declare historyFrom: string | null;
|
|
}
|
|
export class StockSearchResultDto extends StockDto {
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare price: MoneyDto | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
|
declare priceAt: string | null;
|
|
}
|
|
export class StockQuoteDto {
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare price: MoneyDto | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
|
declare priceAt: string | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare tradingStatus:
|
|
string | null;
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare change: MoneyDto | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare changePercent:
|
|
string | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date' })
|
|
declare previousCloseDate: string | null;
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare previousClose: MoneyDto | null;
|
|
@ApiProperty({ type: [String] }) declare unavailable: string[];
|
|
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
|
}
|
|
export class StockCandleDto {
|
|
@ApiProperty({ format: 'date-time' }) declare time: string;
|
|
@ApiProperty() declare close: string;
|
|
@ApiProperty() declare isComplete: boolean;
|
|
}
|
|
export class StockCandlesDto {
|
|
@ApiProperty({ type: [StockCandleDto] }) declare candles: StockCandleDto[];
|
|
@ApiProperty({ type: String, nullable: true }) declare currency:
|
|
string | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
|
declare historyFrom: string | null;
|
|
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
|
}
|
|
export class StockPositionRowDto extends PortfolioPositionDto {
|
|
@ApiProperty({ type: String, nullable: true }) declare returnPercent:
|
|
string | null;
|
|
}
|
|
export class StockPositionDto {
|
|
@ApiProperty() declare quantity: string;
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare currentValue: MoneyDto | null;
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare averagePurchasePrice: MoneyDto | null;
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare absoluteReturn: MoneyDto | null;
|
|
@ApiProperty({ type: String, nullable: true }) declare returnPercent:
|
|
string | null;
|
|
@ApiProperty({ type: [StockPositionRowDto] })
|
|
declare accounts: StockPositionRowDto[];
|
|
@ApiProperty() declare isStale: boolean;
|
|
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
|
}
|
|
export class StockMetricDto {
|
|
@ApiProperty() declare key: string;
|
|
@ApiProperty() declare value: number;
|
|
@ApiProperty({ enum: ['money', 'ratio', 'percent'] }) declare unit:
|
|
'money' | 'ratio' | 'percent';
|
|
@ApiProperty({ type: String, nullable: true }) declare currency:
|
|
string | null;
|
|
@ApiProperty({ type: String, nullable: true, enum: ['TTM', 'MRQ'] })
|
|
declare period: 'TTM' | 'MRQ' | null;
|
|
}
|
|
export class StockCompanyDto {
|
|
@ApiProperty({ type: String, nullable: true }) declare description:
|
|
string | null;
|
|
@ApiProperty({ type: [StockMetricDto] }) declare metrics: StockMetricDto[];
|
|
@ApiProperty({ type: [String] }) declare unavailable: string[];
|
|
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
|
}
|
|
export class StockDividendDto {
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare perShare: MoneyDto | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date' })
|
|
declare recordDate: string | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date' })
|
|
declare lastBuyDate: string | null;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date' })
|
|
declare paymentDate: string | null;
|
|
@ApiProperty({ enum: ['upcoming', 'past', 'undated'] }) declare timing:
|
|
'upcoming' | 'past' | 'undated';
|
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
|
declare estimatedAmount: MoneyDto | null;
|
|
}
|
|
export class StockDividendsDto {
|
|
@ApiProperty({ type: [StockDividendDto] })
|
|
declare dividends: StockDividendDto[];
|
|
@ApiProperty({ format: 'date' }) declare from: string;
|
|
@ApiProperty({ format: 'date' }) declare to: string;
|
|
@ApiProperty({ format: 'date-time' }) declare observedAt: string;
|
|
@ApiProperty({ type: String, nullable: true, format: 'date-time' })
|
|
declare positionAt: string | null;
|
|
@ApiProperty() declare estimateUnavailable: boolean;
|
|
@ApiProperty() declare positionIsStale: boolean;
|
|
}
|
|
|
|
export class StockPositionResourceDto {
|
|
@ApiProperty({ type: StockPositionDto, nullable: true })
|
|
declare data: StockPositionDto | null;
|
|
@ApiProperty({ type: InvestmentResourceMetaDto })
|
|
declare meta: InvestmentResourceMetaDto;
|
|
}
|
|
|
|
export class StockSearchResourceDto {
|
|
@ApiProperty({ type: StockSearchResultDto, isArray: true, nullable: true })
|
|
declare data: StockSearchResultDto[] | null;
|
|
@ApiProperty({ type: InvestmentResourceMetaDto })
|
|
declare meta: InvestmentResourceMetaDto;
|
|
}
|
|
|
|
export class StockResourceDto {
|
|
@ApiProperty({ type: StockDto, nullable: true })
|
|
declare data: StockDto | null;
|
|
@ApiProperty({ type: InvestmentResourceMetaDto })
|
|
declare meta: InvestmentResourceMetaDto;
|
|
}
|
|
|
|
export class StockQuoteResourceDto {
|
|
@ApiProperty({ type: StockQuoteDto, nullable: true })
|
|
declare data: StockQuoteDto | null;
|
|
@ApiProperty({ type: InvestmentResourceMetaDto })
|
|
declare meta: InvestmentResourceMetaDto;
|
|
}
|
|
|
|
export class StockCompanyResourceDto {
|
|
@ApiProperty({ type: StockCompanyDto, nullable: true })
|
|
declare data: StockCompanyDto | null;
|
|
@ApiProperty({ type: InvestmentResourceMetaDto })
|
|
declare meta: InvestmentResourceMetaDto;
|
|
}
|
|
|
|
export class StockCandlesResourceDto {
|
|
@ApiProperty({ type: StockCandlesDto, nullable: true })
|
|
declare data: StockCandlesDto | null;
|
|
@ApiProperty({ type: InvestmentResourceMetaDto })
|
|
declare meta: InvestmentResourceMetaDto;
|
|
}
|
|
|
|
export class StockDividendsResourceDto {
|
|
@ApiProperty({ type: StockDividendsDto, nullable: true })
|
|
declare data: StockDividendsDto | null;
|
|
@ApiProperty({ type: InvestmentResourceMetaDto })
|
|
declare meta: InvestmentResourceMetaDto;
|
|
}
|