41 lines
1.7 KiB
Python
41 lines
1.7 KiB
Python
from __future__ import annotations
|
||
|
||
from datetime import date
|
||
from decimal import Decimal
|
||
|
||
from sqlalchemy import BigInteger, Boolean, Date, ForeignKey, Integer, String, true
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.core.config import settings
|
||
from app.db.base import Base
|
||
from app.db.types import AuditMixin, IdMixin, Percent, Price, qualified
|
||
|
||
|
||
class Security(IdMixin, AuditMixin, Base):
|
||
"""Облигация. isin — идентификатор для пользователя, secid — для запросов к ISS.
|
||
|
||
У корпоративных бумаг secid обычно совпадает с ISIN, у ОФЗ — нет
|
||
(например, SU26238RMFS4), поэтому храним оба.
|
||
"""
|
||
|
||
__tablename__ = "security"
|
||
__table_args__ = (
|
||
{"schema": settings.DATABASE_SCHEMA} if settings.DATABASE_SCHEMA else {}
|
||
)
|
||
|
||
isin: Mapped[str] = mapped_column(String(12), unique=True, nullable=False)
|
||
secid: Mapped[str] = mapped_column(String(51), nullable=False)
|
||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||
initial_face_value: Mapped[Decimal | None] = mapped_column(Price)
|
||
currency_id: Mapped[int] = mapped_column(
|
||
BigInteger, ForeignKey(qualified("currency.id")), nullable=False
|
||
)
|
||
placement_date: Mapped[date | None] = mapped_column(Date)
|
||
maturity_date: Mapped[date | None] = mapped_column(Date)
|
||
coupon_rate: Mapped[Decimal | None] = mapped_column(Percent)
|
||
coupon_frequency: Mapped[int | None] = mapped_column(Integer)
|
||
# TODO(BIQ-38115): заменится признаком «есть позиция в портфеле».
|
||
is_active: Mapped[bool] = mapped_column(
|
||
Boolean, nullable=False, default=True, server_default=true()
|
||
)
|