"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""

from __future__ import annotations
from .agreement import Agreement, AgreementTypedDict
from .enrollment import Enrollment, EnrollmentTypedDict
from .identifier import Identifier, IdentifierTypedDict
from .interestedparty import InterestedParty, InterestedPartyTypedDict
from .party import Party, PartyTypedDict
from .trustedcontact import TrustedContact, TrustedContactTypedDict
from ascend_sdk import utils
from ascend_sdk.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
)
from ascend_sdk.utils import validate_open_enum
from datetime import datetime
from enum import Enum
from pydantic import model_serializer
from pydantic.functional_validators import PlainValidator
from typing import List, Optional
from typing_extensions import Annotated, NotRequired, TypedDict


class AccountCatAccountHolderType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The FINRA CAT classification for the Account Holder; Is set automatically based on attributes of the owners and account type"""

    CAT_ACCOUNT_HOLDER_TYPE_UNSPECIFIED = "CAT_ACCOUNT_HOLDER_TYPE_UNSPECIFIED"
    A_INSTITUTIONAL_CUSTOMER = "A_INSTITUTIONAL_CUSTOMER"
    E_EMPLOYEE_ACCOUNT = "E_EMPLOYEE_ACCOUNT"
    F_FOREIGN = "F_FOREIGN"
    I_INDIVIDUAL = "I_INDIVIDUAL"
    O_MARKET_MAKING = "O_MARKET_MAKING"
    V_AGENCY_AVERAGE_PRICE_ACCOUNT = "V_AGENCY_AVERAGE_PRICE_ACCOUNT"
    P_OTHER_PROPRIETARY = "P_OTHER_PROPRIETARY"
    X_ERROR_ACCOUNT = "X_ERROR_ACCOUNT"


class Domicile(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Indicates if the account is `DOMESTIC` or `FOREIGN`"""

    DOMICILE_UNSPECIFIED = "DOMICILE_UNSPECIFIED"
    DOMESTIC = "DOMESTIC"
    FOREIGN = "FOREIGN"


class FinraCoaCode(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The FINRA COA code associated with the account"""

    FINRA_COA_CODE_UNSPECIFIED = "FINRA_COA_CODE_UNSPECIFIED"
    CAT_01_CUSTOMER_DVP_RVP = "CAT_01_CUSTOMER_DVP_RVP"
    CAT_02_CUSTOMER_MANAGED_ACCOUNTS = "CAT_02_CUSTOMER_MANAGED_ACCOUNTS"
    CAT_03_CUSTOMER_IRA_ACCOUNTS = "CAT_03_CUSTOMER_IRA_ACCOUNTS"
    CAT_04_CUSTOMER_EMPLOYEE = "CAT_04_CUSTOMER_EMPLOYEE"
    CAT_05_CUSTOMER_PRIME_BROKER = "CAT_05_CUSTOMER_PRIME_BROKER"
    CAT_06_CUSTOMER_AFFILIATE_NON_BD = "CAT_06_CUSTOMER_AFFILIATE_NON_BD"
    CAT_07_CUSTOMER_OMNIBUS = "CAT_07_CUSTOMER_OMNIBUS"
    CAT_08_CUSTOMER = "CAT_08_CUSTOMER"
    CAT_09_NON_CUSTOMER_OFFICER_DIRECTOR = "CAT_09_NON_CUSTOMER_OFFICER_DIRECTOR"
    CAT_10_NON_CUSTOMER_OFFICER_DIRECTOR_OR_FAMILY_MEMBERS = (
        "CAT_10_NON_CUSTOMER_OFFICER_DIRECTOR_OR_FAMILY_MEMBERS"
    )
    CAT_11_NON_CUSTOMER_AFFILIATE_BD = "CAT_11_NON_CUSTOMER_AFFILIATE_BD"
    CAT_12_NON_CUSTOMER_OMNIBUS = "CAT_12_NON_CUSTOMER_OMNIBUS"
    CAT_13_NON_CUSTOMER = "CAT_13_NON_CUSTOMER"
    CAT_14_PAIB = "CAT_14_PAIB"
    CAT_15_FIRM_INVENTORY = "CAT_15_FIRM_INVENTORY"
    CAT_16_CNS_FAILS = "CAT_16_CNS_FAILS"
    CAT_17_OTHER_CLEARING_CORP_FAILS = "CAT_17_OTHER_CLEARING_CORP_FAILS"
    CAT_18_EXECUTING_PRIME_BROKER = "CAT_18_EXECUTING_PRIME_BROKER"
    CAT_19_BROKER_FAILS_TO_RECEIVE = "CAT_19_BROKER_FAILS_TO_RECEIVE"
    CAT_20_BROKER_FAILS_TO_DELIVER = "CAT_20_BROKER_FAILS_TO_DELIVER"
    CAT_21_BROKER_FAILS = "CAT_21_BROKER_FAILS"
    CAT_22_FAIL_TO_DELIVER_GREATER_THAN_30_DAYS = (
        "CAT_22_FAIL_TO_DELIVER_GREATER_THAN_30_DAYS"
    )
    CAT_23_SECURITIES_BORROWED = "CAT_23_SECURITIES_BORROWED"
    CAT_24_SECURITIES_BORROWED_NON_CASH = "CAT_24_SECURITIES_BORROWED_NON_CASH"
    CAT_25_SECURITIES_BORROWED_CONDUIT = "CAT_25_SECURITIES_BORROWED_CONDUIT"
    CAT_26_SECURITIES_LOANED = "CAT_26_SECURITIES_LOANED"
    CAT_27_SECURITIES_LOANED_NON_CASH = "CAT_27_SECURITIES_LOANED_NON_CASH"
    CAT_28_SECURITIES_LOANED_CONDUIT = "CAT_28_SECURITIES_LOANED_CONDUIT"
    CAT_29_SECURITIES_LOANED_CNS = "CAT_29_SECURITIES_LOANED_CNS"
    CAT_30_REVERSE_REPO = "CAT_30_REVERSE_REPO"
    CAT_31_REVERSE_REPO_TRI_PARTY = "CAT_31_REVERSE_REPO_TRI_PARTY"
    CAT_32_REPO = "CAT_32_REPO"
    CAT_33_REPO_HOLD_IN_CUSTODY = "CAT_33_REPO_HOLD_IN_CUSTODY"
    CAT_34_REPO_TRI_PARTY = "CAT_34_REPO_TRI_PARTY"
    CAT_35_BANK_LOAN_FIRM = "CAT_35_BANK_LOAN_FIRM"
    CAT_36_BANK_LOAN_CUSTOMER = "CAT_36_BANK_LOAN_CUSTOMER"
    CAT_37_BANK_LOAN_NON_CUSTOMER = "CAT_37_BANK_LOAN_NON_CUSTOMER"
    CAT_38_BANK_LOAN_PAIB = "CAT_38_BANK_LOAN_PAIB"
    CAT_39_SUSPENSE = "CAT_39_SUSPENSE"
    CAT_40_REORGANIZATIONS = "CAT_40_REORGANIZATIONS"
    CAT_41_STOCK_DIVIDENDS = "CAT_41_STOCK_DIVIDENDS"
    CAT_42_ABANDONED_PROPERTY = "CAT_42_ABANDONED_PROPERTY"
    CAT_43_PHYSICAL_BOX = "CAT_43_PHYSICAL_BOX"
    CAT_44_LEGAL_BOX = "CAT_44_LEGAL_BOX"
    CAT_45_SAFEKEEPING = "CAT_45_SAFEKEEPING"
    CAT_46_15_C3_3_DEPOSIT = "CAT_46_15C3_3_DEPOSIT"
    CAT_47_DOMESTIC_DEPOSITORY_CONTROL = "CAT_47_DOMESTIC_DEPOSITORY_CONTROL"
    CAT_48_FOREIGN_DEPOSITORY_CONTROL = "CAT_48_FOREIGN_DEPOSITORY_CONTROL"
    CAT_49_DOMESTIC_DEPOSITORY_NON_CONTROL = "CAT_49_DOMESTIC_DEPOSITORY_NON_CONTROL"
    CAT_50_FOREIGN_DEPOSITORY_NON_CONTROL = "CAT_50_FOREIGN_DEPOSITORY_NON_CONTROL"
    CAT_51_TRANSFER_CONTROL = "CAT_51_TRANSFER_CONTROL"
    CAT_52_TRANSFER_NON_CONTROL = "CAT_52_TRANSFER_NON_CONTROL"
    CAT_53_TRANSFER_LEGAL = "CAT_53_TRANSFER_LEGAL"
    CAT_54_IN_TRANSIT_CONTROL = "CAT_54_IN_TRANSIT_CONTROL"
    CAT_55_IN_TRANSIT_NON_CONTROL = "CAT_55_IN_TRANSIT_NON_CONTROL"
    CAT_56_CLEARING_DOMESTIC = "CAT_56_CLEARING_DOMESTIC"
    CAT_57_CLEARING_FOREIGN = "CAT_57_CLEARING_FOREIGN"
    CAT_58_TEST_ACCOUNT = "CAT_58_TEST_ACCOUNT"
    CAT_59_OUT_OF_BALANCE = "CAT_59_OUT_OF_BALANCE"
    CAT_60_CONVERSION = "CAT_60_CONVERSION"
    CAT_61_DEPOSITS_OCC_MARGIN = "CAT_61_DEPOSITS_OCC_MARGIN"
    CAT_62_DEPOSITS_OTHER = "CAT_62_DEPOSITS_OTHER"
    CAT_63_OTHER = "CAT_63_OTHER"


class FundingType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Describes if the account is cash-only or has access to a form of margin"""

    FUNDING_TYPE_UNSPECIFIED = "FUNDING_TYPE_UNSPECIFIED"
    CASH = "CASH"
    MARGIN_LIMITED_PURPOSE = "MARGIN_LIMITED_PURPOSE"
    MARGIN_REG_T = "MARGIN_REG_T"
    MARGIN_PORTFOLIO = "MARGIN_PORTFOLIO"


class AccountInvestmentObjective(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The financial goal or purpose that an investor has in mind when making investment decisions; firms often ask investors to specify their investment objectives when opening an account, in order to provide appropriate investment recommendations and manage risk appropriately"""

    INVESTMENT_OBJECTIVE_UNSPECIFIED = "INVESTMENT_OBJECTIVE_UNSPECIFIED"
    BALANCED = "BALANCED"
    CAPITAL_APPRECIATION = "CAPITAL_APPRECIATION"
    CAPITAL_PRESERVATION = "CAPITAL_PRESERVATION"
    GROWTH = "GROWTH"
    GROWTH_AND_INCOME = "GROWTH_AND_INCOME"
    GROWTH_INCOME = "GROWTH_INCOME"
    INCOME = "INCOME"
    LONG_TERM_GROWTH_WITH_GREATER_RISK = "LONG_TERM_GROWTH_WITH_GREATER_RISK"
    LONG_TERM_GROWTH_WITH_SAFETY = "LONG_TERM_GROWTH_WITH_SAFETY"
    MAXIMUM_GROWTH = "MAXIMUM_GROWTH"
    SHORT_TERM_GROWTH_WITH_RISK = "SHORT_TERM_GROWTH_WITH_RISK"
    SPECULATION = "SPECULATION"
    OTHER = "OTHER"


class AccountLiquidityNeeds(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""An investor’s short-term cash requirements or the need to access funds quickly; it is important to consider an investor’s liquidity needs to ensure that they have sufficient cash or easily liquidated assets available to meet their financial obligations - this may include holding cash or cash equivalents"""

    LIQUIDITY_NEEDS_UNSPECIFIED = "LIQUIDITY_NEEDS_UNSPECIFIED"
    VERY_IMPORTANT = "VERY_IMPORTANT"
    SOMEWHAT_IMPORTANT = "SOMEWHAT_IMPORTANT"
    NOT_IMPORTANT = "NOT_IMPORTANT"


class AccountRiskTolerance(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""An investor’s willingness and ability to tolerate risk when making investment decisions; reflects the investor’s comfort level with the potential ups and downs of the market and their ability to withstand potential losses"""

    RISK_TOLERANCE_UNSPECIFIED = "RISK_TOLERANCE_UNSPECIFIED"
    LOW = "LOW"
    MEDIUM = "MEDIUM"
    HIGH = "HIGH"


class AccountTimeHorizon(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""TThe length of time an investor expects to hold an investment before selling it; this can affect the appropriate asset allocation and risk level for the portfolio"""

    TIME_HORIZON_UNSPECIFIED = "TIME_HORIZON_UNSPECIFIED"
    SHORT = "SHORT"
    AVERAGE = "AVERAGE"
    LONG = "LONG"


class AccountGoalsTypedDict(TypedDict):
    r"""Account goals."""

    investment_objective: NotRequired[AccountInvestmentObjective]
    r"""The financial goal or purpose that an investor has in mind when making investment decisions; firms often ask investors to specify their investment objectives when opening an account, in order to provide appropriate investment recommendations and manage risk appropriately"""
    liquidity_needs: NotRequired[AccountLiquidityNeeds]
    r"""An investor’s short-term cash requirements or the need to access funds quickly; it is important to consider an investor’s liquidity needs to ensure that they have sufficient cash or easily liquidated assets available to meet their financial obligations - this may include holding cash or cash equivalents"""
    risk_tolerance: NotRequired[AccountRiskTolerance]
    r"""An investor’s willingness and ability to tolerate risk when making investment decisions; reflects the investor’s comfort level with the potential ups and downs of the market and their ability to withstand potential losses"""
    time_horizon: NotRequired[AccountTimeHorizon]
    r"""TThe length of time an investor expects to hold an investment before selling it; this can affect the appropriate asset allocation and risk level for the portfolio"""


class AccountGoals(BaseModel):
    r"""Account goals."""

    investment_objective: Annotated[
        Optional[AccountInvestmentObjective], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The financial goal or purpose that an investor has in mind when making investment decisions; firms often ask investors to specify their investment objectives when opening an account, in order to provide appropriate investment recommendations and manage risk appropriately"""

    liquidity_needs: Annotated[
        Optional[AccountLiquidityNeeds], PlainValidator(validate_open_enum(False))
    ] = None
    r"""An investor’s short-term cash requirements or the need to access funds quickly; it is important to consider an investor’s liquidity needs to ensure that they have sufficient cash or easily liquidated assets available to meet their financial obligations - this may include holding cash or cash equivalents"""

    risk_tolerance: Annotated[
        Optional[AccountRiskTolerance], PlainValidator(validate_open_enum(False))
    ] = None
    r"""An investor’s willingness and ability to tolerate risk when making investment decisions; reflects the investor’s comfort level with the potential ups and downs of the market and their ability to withstand potential losses"""

    time_horizon: Annotated[
        Optional[AccountTimeHorizon], PlainValidator(validate_open_enum(False))
    ] = None
    r"""TThe length of time an investor expects to hold an investment before selling it; this can affect the appropriate asset allocation and risk level for the portfolio"""


class AccountAnnualIncomeRangeUsd(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Annual income range; the low number is exclusive, the high number is inclusive"""

    USD_RANGE_UNSPECIFIED = "USD_RANGE_UNSPECIFIED"
    UNDER_25_K = "UNDER_25K"
    FROM_25_K_TO_50_K = "FROM_25K_TO_50K"
    FROM_50_K_TO_100_K = "FROM_50K_TO_100K"
    FROM_100_K_TO_200_K = "FROM_100K_TO_200K"
    FROM_200_K_TO_300_K = "FROM_200K_TO_300K"
    FROM_300_K_TO_500_K = "FROM_300K_TO_500K"
    FROM_500_K_TO_1_M = "FROM_500K_TO_1M"
    FROM_1_M_TO_5_M = "FROM_1M_TO_5M"
    OVER_5_M = "OVER_5M"


class AccountInvestmentExperience(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Investment experience."""

    INVESTMENT_EXPERIENCE_UNSPECIFIED = "INVESTMENT_EXPERIENCE_UNSPECIFIED"
    NONE = "NONE"
    LIMITED = "LIMITED"
    GOOD = "GOOD"
    EXTENSIVE = "EXTENSIVE"


class AccountLiquidNetWorthRangeUsd(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Liquid net worth range; the low number is exclusive, the high number is inclusive"""

    USD_RANGE_UNSPECIFIED = "USD_RANGE_UNSPECIFIED"
    UNDER_25_K = "UNDER_25K"
    FROM_25_K_TO_50_K = "FROM_25K_TO_50K"
    FROM_50_K_TO_100_K = "FROM_50K_TO_100K"
    FROM_100_K_TO_200_K = "FROM_100K_TO_200K"
    FROM_200_K_TO_300_K = "FROM_200K_TO_300K"
    FROM_300_K_TO_500_K = "FROM_300K_TO_500K"
    FROM_500_K_TO_1_M = "FROM_500K_TO_1M"
    FROM_1_M_TO_5_M = "FROM_1M_TO_5M"
    OVER_5_M = "OVER_5M"


class AccountTotalNetWorthRangeUsd(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Total net worth range; the low number is exclusive, the high number is inclusive"""

    USD_RANGE_UNSPECIFIED = "USD_RANGE_UNSPECIFIED"
    UNDER_25_K = "UNDER_25K"
    FROM_25_K_TO_50_K = "FROM_25K_TO_50K"
    FROM_50_K_TO_100_K = "FROM_50K_TO_100K"
    FROM_100_K_TO_200_K = "FROM_100K_TO_200K"
    FROM_200_K_TO_300_K = "FROM_200K_TO_300K"
    FROM_300_K_TO_500_K = "FROM_300K_TO_500K"
    FROM_500_K_TO_1_M = "FROM_500K_TO_1M"
    FROM_1_M_TO_5_M = "FROM_1M_TO_5M"
    OVER_5_M = "OVER_5M"


class CustomerProfileTypedDict(TypedDict):
    r"""Customer profile."""

    annual_income_range_usd: NotRequired[AccountAnnualIncomeRangeUsd]
    r"""Annual income range; the low number is exclusive, the high number is inclusive"""
    federal_tax_bracket: NotRequired[float]
    r"""Federal tax bracket percent."""
    investment_experience: NotRequired[AccountInvestmentExperience]
    r"""Investment experience."""
    liquid_net_worth_range_usd: NotRequired[AccountLiquidNetWorthRangeUsd]
    r"""Liquid net worth range; the low number is exclusive, the high number is inclusive"""
    total_net_worth_range_usd: NotRequired[AccountTotalNetWorthRangeUsd]
    r"""Total net worth range; the low number is exclusive, the high number is inclusive"""


class CustomerProfile(BaseModel):
    r"""Customer profile."""

    annual_income_range_usd: Annotated[
        Optional[AccountAnnualIncomeRangeUsd], PlainValidator(validate_open_enum(False))
    ] = None
    r"""Annual income range; the low number is exclusive, the high number is inclusive"""

    federal_tax_bracket: Optional[float] = None
    r"""Federal tax bracket percent."""

    investment_experience: Annotated[
        Optional[AccountInvestmentExperience], PlainValidator(validate_open_enum(False))
    ] = None
    r"""Investment experience."""

    liquid_net_worth_range_usd: Annotated[
        Optional[AccountLiquidNetWorthRangeUsd],
        PlainValidator(validate_open_enum(False)),
    ] = None
    r"""Liquid net worth range; the low number is exclusive, the high number is inclusive"""

    total_net_worth_range_usd: Annotated[
        Optional[AccountTotalNetWorthRangeUsd],
        PlainValidator(validate_open_enum(False)),
    ] = None
    r"""Total net worth range; the low number is exclusive, the high number is inclusive"""


class InvestmentProfileTypedDict(TypedDict):
    r"""The account's goals and customer's financial profile; Used to assess customer fitness and is required by FINRA"""

    account_goals: NotRequired[Nullable[AccountGoalsTypedDict]]
    r"""Account goals."""
    customer_profile: NotRequired[Nullable[CustomerProfileTypedDict]]
    r"""Customer profile."""
    investment_profile_id: NotRequired[str]
    r"""The investment profile ID (generated internally)."""


class InvestmentProfile(BaseModel):
    r"""The account's goals and customer's financial profile; Used to assess customer fitness and is required by FINRA"""

    account_goals: OptionalNullable[AccountGoals] = UNSET
    r"""Account goals."""

    customer_profile: OptionalNullable[CustomerProfile] = UNSET
    r"""Customer profile."""

    investment_profile_id: Optional[str] = None
    r"""The investment profile ID (generated internally)."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = ["account_goals", "customer_profile", "investment_profile_id"]
        nullable_fields = ["account_goals", "customer_profile"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class OwnershipType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""A roll-up account classification based on the `registration_type`; Indicates what owns the account and/or if it is a special type (e.g., Joint, Estate, Retirement, etc.); Used primarily for reporting and high-level type identification"""

    OWNERSHIP_TYPE_UNSPECIFIED = "OWNERSHIP_TYPE_UNSPECIFIED"
    INDIVIDUAL = "INDIVIDUAL"
    JOINT = "JOINT"
    ESTATE = "ESTATE"
    RETIREMENT = "RETIREMENT"
    TRUST = "TRUST"
    ENTITY = "ENTITY"
    MINOR = "MINOR"


class RegistrationType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The registration of the account (e.g. Individual, Joint, IRA, etc.)"""

    REGISTRATION_TYPE_UNSPECIFIED = "REGISTRATION_TYPE_UNSPECIFIED"
    INDIVIDUAL_REGISTRATION = "INDIVIDUAL_REGISTRATION"
    ESTATE_REGISTRATION = "ESTATE_REGISTRATION"
    TRADITIONAL_IRA_REGISTRATION = "TRADITIONAL_IRA_REGISTRATION"
    SIMPLE_IRA_REGISTRATION = "SIMPLE_IRA_REGISTRATION"
    SEP_IRA_REGISTRATION = "SEP_IRA_REGISTRATION"
    ROTH_IRA_REGISTRATION = "ROTH_IRA_REGISTRATION"
    ROLLOVER_IRA_REGISTRATION = "ROLLOVER_IRA_REGISTRATION"
    JOINT_WITH_RIGHTS_OF_SURVIVORSHIP_REGISTRATION = (
        "JOINT_WITH_RIGHTS_OF_SURVIVORSHIP_REGISTRATION"
    )
    JOINT_TENANTS_IN_COMMON_REGISTRATION = "JOINT_TENANTS_IN_COMMON_REGISTRATION"
    JOINT_TENANTS_BY_ENTIRETY_REGISTRATION = "JOINT_TENANTS_BY_ENTIRETY_REGISTRATION"
    JOINT_COMMUNITY_PROPERTY_REGISTRATION = "JOINT_COMMUNITY_PROPERTY_REGISTRATION"
    TRUST_REGISTRATION = "TRUST_REGISTRATION"
    CORPORATION_REGISTRATION = "CORPORATION_REGISTRATION"
    LLC_REGISTRATION = "LLC_REGISTRATION"
    PARTNERSHIP_REGISTRATION = "PARTNERSHIP_REGISTRATION"
    OPERATING_REGISTRATION = "OPERATING_REGISTRATION"
    IRA_BENEFICIARY_TRADITIONAL_REGISTRATION = (
        "IRA_BENEFICIARY_TRADITIONAL_REGISTRATION"
    )
    IRA_BENEFICIARY_ROTH_REGISTRATION = "IRA_BENEFICIARY_ROTH_REGISTRATION"
    CUSTODIAL_REGISTRATION = "CUSTODIAL_REGISTRATION"


class ReserveClass(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The Reserve Class associated with the account"""

    RESERVE_CLASS_UNSPECIFIED = "RESERVE_CLASS_UNSPECIFIED"
    CUSTOMER = "CUSTOMER"
    PAB = "PAB"
    FIRM = "FIRM"
    STREET = "STREET"
    G_L = "G_L"


class AccountState(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Indicates if the account is `OPEN`, `PENDING`, or `CLOSED`"""

    STATE_UNSPECIFIED = "STATE_UNSPECIFIED"
    PENDING = "PENDING"
    OPEN = "OPEN"
    CLOSED = "CLOSED"


class AccountCostBasisLotDisposalMethod(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""A method of determining the cost basis of an asset that has been sold or disposed of, by identifying which specific lot of the asset was sold and using the cost of that lot to calculate the cost basis; this method is commonly used for tax purposes to determine the amount of reportable capital gains or losses By default, this is set to `COST_BASIS_LOT_DISPOSAL_MIN_TAX_TERM`"""

    COST_BASIS_LOT_DISPOSAL_METHOD_UNSPECIFIED = (
        "COST_BASIS_LOT_DISPOSAL_METHOD_UNSPECIFIED"
    )
    COST_BASIS_LOT_DISPOSAL_FIFO = "COST_BASIS_LOT_DISPOSAL_FIFO"
    COST_BASIS_LOT_DISPOSAL_LIFO = "COST_BASIS_LOT_DISPOSAL_LIFO"
    COST_BASIS_LOT_DISPOSAL_HIGH_COST = "COST_BASIS_LOT_DISPOSAL_HIGH_COST"
    COST_BASIS_LOT_DISPOSAL_HIGH_COST_LONG_TERM = (
        "COST_BASIS_LOT_DISPOSAL_HIGH_COST_LONG_TERM"
    )
    COST_BASIS_LOT_DISPOSAL_HIGH_COST_SHORT_TERM = (
        "COST_BASIS_LOT_DISPOSAL_HIGH_COST_SHORT_TERM"
    )
    COST_BASIS_LOT_DISPOSAL_LOW_COST = "COST_BASIS_LOT_DISPOSAL_LOW_COST"
    COST_BASIS_LOT_DISPOSAL_LOW_COST_LONG_TERM = (
        "COST_BASIS_LOT_DISPOSAL_LOW_COST_LONG_TERM"
    )
    COST_BASIS_LOT_DISPOSAL_LOW_COST_SHORT_TERM = (
        "COST_BASIS_LOT_DISPOSAL_LOW_COST_SHORT_TERM"
    )
    COST_BASIS_LOT_DISPOSAL_MIN_TAX_TERM = "COST_BASIS_LOT_DISPOSAL_MIN_TAX_TERM"


class AccountTaxProfileTypedDict(TypedDict):
    r"""Tax-related attributes for the account; A tax profile with taxpayer attributes is located on the `legal_natural_person` or `legal_entity` objects elsewhere on the account record"""

    cost_basis_lot_disposal_method: NotRequired[AccountCostBasisLotDisposalMethod]
    r"""A method of determining the cost basis of an asset that has been sold or disposed of, by identifying which specific lot of the asset was sold and using the cost of that lot to calculate the cost basis; this method is commonly used for tax purposes to determine the amount of reportable capital gains or losses By default, this is set to `COST_BASIS_LOT_DISPOSAL_MIN_TAX_TERM`"""
    section_475_election: NotRequired[bool]
    r"""Indicates if the account is eligible to mark-to-market their securities and commodities holdings; Named after the related section of the IRS tax code"""


class AccountTaxProfile(BaseModel):
    r"""Tax-related attributes for the account; A tax profile with taxpayer attributes is located on the `legal_natural_person` or `legal_entity` objects elsewhere on the account record"""

    cost_basis_lot_disposal_method: Annotated[
        Optional[AccountCostBasisLotDisposalMethod],
        PlainValidator(validate_open_enum(False)),
    ] = None
    r"""A method of determining the cost basis of an asset that has been sold or disposed of, by identifying which specific lot of the asset was sold and using the cost of that lot to calculate the cost basis; this method is commonly used for tax purposes to determine the amount of reportable capital gains or losses By default, this is set to `COST_BASIS_LOT_DISPOSAL_MIN_TAX_TERM`"""

    section_475_election: Optional[bool] = None
    r"""Indicates if the account is eligible to mark-to-market their securities and commodities holdings; Named after the related section of the IRS tax code"""


class AccountTypedDict(TypedDict):
    r"""An Account as represented in the account ecosystem."""

    accepts_issuer_direct_communication: NotRequired[bool]
    r"""Indicates if the issuer of a security held by the account is permitted to communicate directly with the shareholder versus through the brokerage firm; This can include sending proxy statements, annual reports, and other important information directly to the shareholder's address on file with the brokerage firm"""
    account_group_id: NotRequired[str]
    r"""An Account Group is a way of segmenting accounts within a Correspondent; It is up to the client to define what these groups are and AFS Operations is responsible for configuring them; If the client requests additional groups/codes, they can be added; Examples of Account Groups could hypothetically include HNW (High Net Worth), GOLD (Gold Status Customer), and NWC (Northwest Branch Customer)"""
    account_id: NotRequired[str]
    r"""A globally unique identifier referencing a single account; This is the main identifier for an account used for machine-to-machine interactions"""
    account_number: NotRequired[str]
    r"""A \"unique\" identifier referencing this single account This should be the human readable identifier for the account used for display"""
    active_restrictions: NotRequired[List[str]]
    r"""The list of restrictions currently impacting a given account; Restrictions suspend one or more entitlements dependent on their mapping"""
    advised: NotRequired[bool]
    r"""A boolean to indicate if an account is advised"""
    agreements: NotRequired[List[AgreementTypedDict]]
    r"""The collection of legal agreements belonging to a given account"""
    cat_account_holder_type: NotRequired[AccountCatAccountHolderType]
    r"""The FINRA CAT classification for the Account Holder; Is set automatically based on attributes of the owners and account type"""
    close_time: NotRequired[Nullable[datetime]]
    r"""The time the account was closed; If the account is not closed, this is null"""
    correspondent_id: NotRequired[str]
    r"""A unique identifier referencing a Correspondent; A Client may have several operating Correspondents within its purview."""
    create_time: NotRequired[Nullable[datetime]]
    r"""The time the initial account record was created; May differ from the `open_time` timestamp which depends on when all required data was provided to the system"""
    domicile: NotRequired[Domicile]
    r"""Indicates if the account is `DOMESTIC` or `FOREIGN`"""
    enrollments: NotRequired[List[EnrollmentTypedDict]]
    r"""A list of enrollments (or \"features\") on an account; May consist of both active an inactive enrollments"""
    fdid: NotRequired[str]
    r"""Apex requires a Firm-Designated ID (FDID) for Consolidated Audit Trail (CAT) reporting and uses it as a unique identifier for each trading account; The identifier cannot be the same as the accountID; Apex automatically assigns this ID."""
    finra_coa_code: NotRequired[FinraCoaCode]
    r"""The FINRA COA code associated with the account"""
    funding_type: NotRequired[FundingType]
    r"""Describes if the account is cash-only or has access to a form of margin"""
    identifiers: NotRequired[List[IdentifierTypedDict]]
    r"""A list of identifiers associated with the account"""
    interested_parties: NotRequired[List[InterestedPartyTypedDict]]
    r"""A list of natural persons indicated to receive selected account documents such as account statements"""
    investment_profile: NotRequired[Nullable[InvestmentProfileTypedDict]]
    r"""The account's goals and customer's financial profile; Used to assess customer fitness and is required by FINRA"""
    managed: NotRequired[bool]
    r"""A boolean to indicate if an account is managed"""
    margin_group_id: NotRequired[str]
    r"""An identifier generated for all non-cash accounts; Uses a combination of account type and owner information to tie accounts together in order to perform margin calculations"""
    name: NotRequired[str]
    r"""The name field Format: accounts/{account}"""
    open_time: NotRequired[Nullable[datetime]]
    r"""The time the account was activated; Differs from `create_time` which is when the initial account record was created"""
    ownership_type: NotRequired[OwnershipType]
    r"""A roll-up account classification based on the `registration_type`; Indicates what owns the account and/or if it is a special type (e.g., Joint, Estate, Retirement, etc.); Used primarily for reporting and high-level type identification"""
    parties: NotRequired[List[PartyTypedDict]]
    r"""Parties associated with the account (e.g. custodian)."""
    pattern_day_trader: NotRequired[bool]
    r"""Indicates if the customer is a PDT; This is set if the account executes four or more day trades (buy and sell the same security intraday) within a period of five business days"""
    primary_registered_rep_id: NotRequired[str]
    r"""The primary registered representative for the account"""
    registration_type: NotRequired[RegistrationType]
    r"""The registration of the account (e.g. Individual, Joint, IRA, etc.)"""
    reserve_class: NotRequired[ReserveClass]
    r"""The Reserve Class associated with the account"""
    state: NotRequired[AccountState]
    r"""Indicates if the account is `OPEN`, `PENDING`, or `CLOSED`"""
    tax_profile: NotRequired[Nullable[AccountTaxProfileTypedDict]]
    r"""Tax-related attributes for the account; A tax profile with taxpayer attributes is located on the `legal_natural_person` or `legal_entity` objects elsewhere on the account record"""
    title: NotRequired[str]
    r"""The title of the account."""
    trusted_contacts: NotRequired[List[TrustedContactTypedDict]]
    r"""A list of persons designated to verify the well being of the account holder."""
    wrap_fee_billed: NotRequired[bool]
    r"""A boolean to indicate if an account is a wrap brokerage account"""


class Account(BaseModel):
    r"""An Account as represented in the account ecosystem."""

    accepts_issuer_direct_communication: Optional[bool] = None
    r"""Indicates if the issuer of a security held by the account is permitted to communicate directly with the shareholder versus through the brokerage firm; This can include sending proxy statements, annual reports, and other important information directly to the shareholder's address on file with the brokerage firm"""

    account_group_id: Optional[str] = None
    r"""An Account Group is a way of segmenting accounts within a Correspondent; It is up to the client to define what these groups are and AFS Operations is responsible for configuring them; If the client requests additional groups/codes, they can be added; Examples of Account Groups could hypothetically include HNW (High Net Worth), GOLD (Gold Status Customer), and NWC (Northwest Branch Customer)"""

    account_id: Optional[str] = None
    r"""A globally unique identifier referencing a single account; This is the main identifier for an account used for machine-to-machine interactions"""

    account_number: Optional[str] = None
    r"""A \"unique\" identifier referencing this single account This should be the human readable identifier for the account used for display"""

    active_restrictions: Optional[List[str]] = None
    r"""The list of restrictions currently impacting a given account; Restrictions suspend one or more entitlements dependent on their mapping"""

    advised: Optional[bool] = None
    r"""A boolean to indicate if an account is advised"""

    agreements: Optional[List[Agreement]] = None
    r"""The collection of legal agreements belonging to a given account"""

    cat_account_holder_type: Annotated[
        Optional[AccountCatAccountHolderType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The FINRA CAT classification for the Account Holder; Is set automatically based on attributes of the owners and account type"""

    close_time: OptionalNullable[datetime] = UNSET
    r"""The time the account was closed; If the account is not closed, this is null"""

    correspondent_id: Optional[str] = None
    r"""A unique identifier referencing a Correspondent; A Client may have several operating Correspondents within its purview."""

    create_time: OptionalNullable[datetime] = UNSET
    r"""The time the initial account record was created; May differ from the `open_time` timestamp which depends on when all required data was provided to the system"""

    domicile: Annotated[
        Optional[Domicile], PlainValidator(validate_open_enum(False))
    ] = None
    r"""Indicates if the account is `DOMESTIC` or `FOREIGN`"""

    enrollments: Optional[List[Enrollment]] = None
    r"""A list of enrollments (or \"features\") on an account; May consist of both active an inactive enrollments"""

    fdid: Optional[str] = None
    r"""Apex requires a Firm-Designated ID (FDID) for Consolidated Audit Trail (CAT) reporting and uses it as a unique identifier for each trading account; The identifier cannot be the same as the accountID; Apex automatically assigns this ID."""

    finra_coa_code: Annotated[
        Optional[FinraCoaCode], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The FINRA COA code associated with the account"""

    funding_type: Annotated[
        Optional[FundingType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""Describes if the account is cash-only or has access to a form of margin"""

    identifiers: Optional[List[Identifier]] = None
    r"""A list of identifiers associated with the account"""

    interested_parties: Optional[List[InterestedParty]] = None
    r"""A list of natural persons indicated to receive selected account documents such as account statements"""

    investment_profile: OptionalNullable[InvestmentProfile] = UNSET
    r"""The account's goals and customer's financial profile; Used to assess customer fitness and is required by FINRA"""

    managed: Optional[bool] = None
    r"""A boolean to indicate if an account is managed"""

    margin_group_id: Optional[str] = None
    r"""An identifier generated for all non-cash accounts; Uses a combination of account type and owner information to tie accounts together in order to perform margin calculations"""

    name: Optional[str] = None
    r"""The name field Format: accounts/{account}"""

    open_time: OptionalNullable[datetime] = UNSET
    r"""The time the account was activated; Differs from `create_time` which is when the initial account record was created"""

    ownership_type: Annotated[
        Optional[OwnershipType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""A roll-up account classification based on the `registration_type`; Indicates what owns the account and/or if it is a special type (e.g., Joint, Estate, Retirement, etc.); Used primarily for reporting and high-level type identification"""

    parties: Optional[List[Party]] = None
    r"""Parties associated with the account (e.g. custodian)."""

    pattern_day_trader: Optional[bool] = None
    r"""Indicates if the customer is a PDT; This is set if the account executes four or more day trades (buy and sell the same security intraday) within a period of five business days"""

    primary_registered_rep_id: Optional[str] = None
    r"""The primary registered representative for the account"""

    registration_type: Annotated[
        Optional[RegistrationType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The registration of the account (e.g. Individual, Joint, IRA, etc.)"""

    reserve_class: Annotated[
        Optional[ReserveClass], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The Reserve Class associated with the account"""

    state: Annotated[
        Optional[AccountState], PlainValidator(validate_open_enum(False))
    ] = None
    r"""Indicates if the account is `OPEN`, `PENDING`, or `CLOSED`"""

    tax_profile: OptionalNullable[AccountTaxProfile] = UNSET
    r"""Tax-related attributes for the account; A tax profile with taxpayer attributes is located on the `legal_natural_person` or `legal_entity` objects elsewhere on the account record"""

    title: Optional[str] = None
    r"""The title of the account."""

    trusted_contacts: Optional[List[TrustedContact]] = None
    r"""A list of persons designated to verify the well being of the account holder."""

    wrap_fee_billed: Optional[bool] = None
    r"""A boolean to indicate if an account is a wrap brokerage account"""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "accepts_issuer_direct_communication",
            "account_group_id",
            "account_id",
            "account_number",
            "active_restrictions",
            "advised",
            "agreements",
            "cat_account_holder_type",
            "close_time",
            "correspondent_id",
            "create_time",
            "domicile",
            "enrollments",
            "fdid",
            "finra_coa_code",
            "funding_type",
            "identifiers",
            "interested_parties",
            "investment_profile",
            "managed",
            "margin_group_id",
            "name",
            "open_time",
            "ownership_type",
            "parties",
            "pattern_day_trader",
            "primary_registered_rep_id",
            "registration_type",
            "reserve_class",
            "state",
            "tax_profile",
            "title",
            "trusted_contacts",
            "wrap_fee_billed",
        ]
        nullable_fields = [
            "close_time",
            "create_time",
            "investment_profile",
            "open_time",
            "tax_profile",
        ]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m
