feat: управление портфелями с разделением акций и облигаций #7

Merged
ksv741 merged 2 commits from feat/portfolio-phase1 into main 2026-06-14 11:17:20 +03:00
5 changed files with 19 additions and 15 deletions
Showing only changes of commit ca4a8b35f3 - Show all commits

View File

@ -3,11 +3,12 @@
"version": "0.0.1",
"private": true,
"scripts": {
"postinstall": "prisma generate",
"build": "nest build",
"start:dev": "nest start --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,test}/**/*.ts\"",
"test": "vitest run",
"test": "VITE_CJS_IGNORE_WARNING=1 vitest run",
"test:watch": "vitest"
},
"dependencies": {

View File

@ -9,10 +9,10 @@ export interface ApiEnvelope<T> {
}
export interface StockMarketData {
price: number;
change: number;
changePercent: number;
open: number;
price: number | null;
change: number | null;
changePercent: number | null;
open: number | null;
high: number | null;
low: number | null;
volume: number;
@ -52,11 +52,11 @@ export interface ShareHistoryItem {
}
export interface BondMarketData {
price: number;
price: number | null;
yieldToMaturity: number | null;
duration: number | null;
accruedInt: number;
couponValue: number;
accruedInt: number | null;
couponValue: number | null;
couponPercent: number | null;
nextCouponDate: string | null;
open: number;

View File

@ -28,7 +28,9 @@ export function BondDetails({ bond }: BondDetailsProps) {
<div style={{ fontSize: 14, color: 'var(--color-text-secondary)' }}>{bond.isin}</div>
</div>
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 4 }}>{md.price.toFixed(2)}%</div>
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 4 }}>
{md.price?.toFixed(2) ?? '—'}%
</div>
<div style={{ marginTop: 16 }}>
<div style={rowStyle}>
@ -44,7 +46,7 @@ export function BondDetails({ bond }: BondDetailsProps) {
<div style={rowStyle}>
<span>Купон</span>
<span>
{md.couponValue} {md.couponPercent != null ? `(${md.couponPercent}%)` : ''}
{md.couponValue ?? '—'} {md.couponPercent != null ? `(${md.couponPercent}%)` : ''}
</span>
</div>
<div style={rowStyle}>
@ -57,7 +59,7 @@ export function BondDetails({ bond }: BondDetailsProps) {
</div>
<div style={rowStyle}>
<span>НКД</span>
<span>{md.accruedInt.toFixed(2)} </span>
<span>{md.accruedInt?.toFixed(2) ?? '—'} </span>
</div>
<div style={rowStyle}>
<span>Доходность к погашению</span>

View File

@ -13,7 +13,7 @@ const rowStyle: React.CSSProperties = {
export function StockDetails({ stock }: StockDetailsProps) {
const md = stock.marketData;
const isPositive = md.change >= 0;
const isPositive = (md.change ?? 0) >= 0;
return (
<div
@ -34,7 +34,7 @@ export function StockDetails({ stock }: StockDetailsProps) {
</div>
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 4 }}>
{md.price.toLocaleString('ru-RU', { minimumFractionDigits: 2 })}{' '}
{md.price?.toLocaleString('ru-RU', { minimumFractionDigits: 2 }) ?? '—'}{' '}
<span
style={{
fontSize: 18,
@ -42,14 +42,14 @@ export function StockDetails({ stock }: StockDetailsProps) {
}}
>
{isPositive ? '+' : ''}
{md.change.toFixed(2)} ({md.changePercent.toFixed(2)}%)
{(md.change ?? 0).toFixed(2)} ({(md.changePercent ?? 0).toFixed(2)}%)
</span>
</div>
<div style={{ marginTop: 16 }}>
<div style={rowStyle}>
<span>Открытие</span>
<span>{md.open.toFixed(2)}</span>
<span>{md.open?.toFixed(2) ?? '—'}</span>
</div>
<div style={rowStyle}>
<span>Максимум</span>

1
package-lock.json generated
View File

@ -19,6 +19,7 @@
"apps/backend": {
"name": "@moex-vibe/backend",
"version": "0.0.1",
"hasInstallScript": true,
"dependencies": {
"@libsql/client": "^0.17.3",
"@nestjs/axios": "^3.0.0",