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

from __future__ import annotations
from .executedprice import ExecutedPrice, ExecutedPriceTypedDict
from .fee import Fee, FeeTypedDict
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 BasketOrderAssetType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The type of the asset in this order"""

    ASSET_TYPE_UNSPECIFIED = "ASSET_TYPE_UNSPECIFIED"
    EQUITY = "EQUITY"
    MUTUAL_FUND = "MUTUAL_FUND"


class BasketOrderCumulativeNotionalValueTypedDict(TypedDict):
    r"""The product of order quantity & price, summed across all fills, reported in the currency specified in the order. (This will be rounded to 2 decimal places for USD currencies). Will be absent if an order has no fill information."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderCumulativeNotionalValue(BaseModel):
    r"""The product of order quantity & price, summed across all fills, reported in the currency specified in the order. (This will be rounded to 2 decimal places for USD currencies). Will be absent if an order has no fill information."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderFilledQuantityTypedDict(TypedDict):
    r"""The summed quantity value across all fills in this order, up to a maximum of 5 decimal places. Will be absent if an order has no fill information."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderFilledQuantity(BaseModel):
    r"""The summed quantity value across all fills in this order, up to a maximum of 5 decimal places. Will be absent if an order has no fill information."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderIdentifierType(str, Enum):
    r"""The identifier type of the asset being ordered. For Equities: only SYMBOL is supported For Mutual Funds: only SYMBOL and CUSIP are supported"""

    SYMBOL = "SYMBOL"
    CUSIP = "CUSIP"
    ISIN = "ISIN"


class BasketOrderAmountTypedDict(TypedDict):
    r"""The amount of the LOI. This is a monetary value in the same currency as the order."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderAmount(BaseModel):
    r"""The amount of the LOI. This is a monetary value in the same currency as the order."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderPeriodStartDateTypedDict(TypedDict):
    r"""The period start date of the LOI."""

    day: NotRequired[int]
    r"""Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 to specify a year by itself or a year and month where the day isn't significant."""
    month: NotRequired[int]
    r"""Month of a year. Must be from 1 to 12, or 0 to specify a year without a month and day."""
    year: NotRequired[int]
    r"""Year of the date. Must be from 1 to 9999, or 0 to specify a date without a year."""


class BasketOrderPeriodStartDate(BaseModel):
    r"""The period start date of the LOI."""

    day: Optional[int] = None
    r"""Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 to specify a year by itself or a year and month where the day isn't significant."""

    month: Optional[int] = None
    r"""Month of a year. Must be from 1 to 12, or 0 to specify a year without a month and day."""

    year: Optional[int] = None
    r"""Year of the date. Must be from 1 to 9999, or 0 to specify a date without a year."""


class BasketOrderLetterOfIntentTypedDict(TypedDict):
    r"""Letter of Intent (LOI). An LOI allows investors to receive sales charge discounts based on a commitment to buy a specified monetary amount of shares over a period of time, usually 13 months. Either ROA or LOI may be specified, but not both."""

    amount: NotRequired[Nullable[BasketOrderAmountTypedDict]]
    r"""The amount of the LOI. This is a monetary value in the same currency as the order."""
    period_start_date: NotRequired[Nullable[BasketOrderPeriodStartDateTypedDict]]
    r"""The period start date of the LOI."""


class BasketOrderLetterOfIntent(BaseModel):
    r"""Letter of Intent (LOI). An LOI allows investors to receive sales charge discounts based on a commitment to buy a specified monetary amount of shares over a period of time, usually 13 months. Either ROA or LOI may be specified, but not both."""

    amount: OptionalNullable[BasketOrderAmount] = UNSET
    r"""The amount of the LOI. This is a monetary value in the same currency as the order."""

    period_start_date: OptionalNullable[BasketOrderPeriodStartDate] = UNSET
    r"""The period start date of the LOI."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = ["amount", "period_start_date"]
        nullable_fields = ["amount", "period_start_date"]
        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 BasketOrderNotionalValueTypedDict(TypedDict):
    r"""Notional quantity of the order, measured in USD. Maximum 2 decimal place precision. Either a quantity or notional_value MUST be specified (but not both). For Equities: currently not supported yet For Mutual Funds: Only supported for BUY orders. The order will be transacted at the full notional amount specified."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderNotionalValue(BaseModel):
    r"""Notional quantity of the order, measured in USD. Maximum 2 decimal place precision. Either a quantity or notional_value MUST be specified (but not both). For Equities: currently not supported yet For Mutual Funds: Only supported for BUY orders. The order will be transacted at the full notional amount specified."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderOrderRejectedReason(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""When an order has the REJECTED status, this will be populated with a system code describing the rejection."""

    ORDER_REJECT_REASON_UNSPECIFIED = "ORDER_REJECT_REASON_UNSPECIFIED"
    BROKER_OPTION = "BROKER_OPTION"
    UNKNOWN_SECURITY = "UNKNOWN_SECURITY"
    EXCHANGE_CLOSED = "EXCHANGE_CLOSED"
    TOO_LATE_TO_ENTER = "TOO_LATE_TO_ENTER"
    UNKNOWN_ORDER = "UNKNOWN_ORDER"
    DUPLICATE_ORDER = "DUPLICATE_ORDER"
    STALE_ORDER = "STALE_ORDER"
    BELOW_NOTIONAL_MINIMUM = "BELOW_NOTIONAL_MINIMUM"
    ACCOUNT_NOT_ENTITLED = "ACCOUNT_NOT_ENTITLED"
    SYSTEM_ERROR = "SYSTEM_ERROR"
    BLOCKING_CORPORATE_ACTION = "BLOCKING_CORPORATE_ACTION"
    UNAVAILABLE_PRICE_QUOTE = "UNAVAILABLE_PRICE_QUOTE"
    EXECUTION_MISCONFIGURED_CLIENT = "EXECUTION_MISCONFIGURED_CLIENT"
    FRACTIONAL_QUANTITY_NOT_ALLOWED_FOR_SECURITY = (
        "FRACTIONAL_QUANTITY_NOT_ALLOWED_FOR_SECURITY"
    )
    ONLY_FRACTIONAL_SELL_OR_WHOLE_ORDERS_ALLOWED_FOR_SECURITY = (
        "ONLY_FRACTIONAL_SELL_OR_WHOLE_ORDERS_ALLOWED_FOR_SECURITY"
    )
    SYMBOL_NOT_TRADEABLE = "SYMBOL_NOT_TRADEABLE"
    ABOVE_NOTIONAL_MAXIMUM = "ABOVE_NOTIONAL_MAXIMUM"
    ABOVE_SHARE_MAXIMUM = "ABOVE_SHARE_MAXIMUM"
    MAX_SELL_QUANTITY_REQUIRED = "MAX_SELL_QUANTITY_REQUIRED"
    MAX_SELL_QUANTITY_PROHIBITED = "MAX_SELL_QUANTITY_PROHIBITED"
    STOCK_TRADES_DISABLED = "STOCK_TRADES_DISABLED"
    ASSET_NOT_SET_UP_TO_TRADE = "ASSET_NOT_SET_UP_TO_TRADE"
    ANOTHER_BASKET_ORDER_FOR_ACCOUNT_HAS_FAILED_RISK_CHECKS = (
        "ANOTHER_BASKET_ORDER_FOR_ACCOUNT_HAS_FAILED_RISK_CHECKS"
    )


class BasketOrderOrderStatus(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The processing status of the order"""

    ORDER_STATUS_UNSPECIFIED = "ORDER_STATUS_UNSPECIFIED"
    PENDING_NEW = "PENDING_NEW"
    NEW = "NEW"
    PARTIALLY_FILLED = "PARTIALLY_FILLED"
    FILLED = "FILLED"
    REJECTED = "REJECTED"


class BasketOrderOrderType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The execution type of this order."""

    ORDER_TYPE_UNSPECIFIED = "ORDER_TYPE_UNSPECIFIED"
    MARKET = "MARKET"


class BasketOrderQuantityTypedDict(TypedDict):
    r"""Numeric quantity of the order. Either a quantity or notional_value MUST be specified (but not both). For Equities: Represents the number of shares, must be greater than zero and may not exceed 5 decimal places. For Mutual Funds: Only supported for SELL orders. Represents the number of shares, up to a maximum of 3 decimal places."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderQuantity(BaseModel):
    r"""Numeric quantity of the order. Either a quantity or notional_value MUST be specified (but not both). For Equities: Represents the number of shares, must be greater than zero and may not exceed 5 decimal places. For Mutual Funds: Only supported for SELL orders. Represents the number of shares, up to a maximum of 3 decimal places."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderRightsOfAccumulationAmountTypedDict(TypedDict):
    r"""The amount of the ROA. This is a monetary value in the same currency as the order. Only 9,999,999.99 is supported."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderRightsOfAccumulationAmount(BaseModel):
    r"""The amount of the ROA. This is a monetary value in the same currency as the order. Only 9,999,999.99 is supported."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class BasketOrderRightsOfAccumulationTypedDict(TypedDict):
    r"""Rights of Accumulation (ROA). An ROA allows an investor to aggregate their own fund shares with the holdings of certain related parties toward achieving the investment thresholds at which sales charge discounts become available. Either ROA or LOI may be specified, but not both."""

    amount: NotRequired[Nullable[BasketOrderRightsOfAccumulationAmountTypedDict]]
    r"""The amount of the ROA. This is a monetary value in the same currency as the order. Only 9,999,999.99 is supported."""


class BasketOrderRightsOfAccumulation(BaseModel):
    r"""Rights of Accumulation (ROA). An ROA allows an investor to aggregate their own fund shares with the holdings of certain related parties toward achieving the investment thresholds at which sales charge discounts become available. Either ROA or LOI may be specified, but not both."""

    amount: OptionalNullable[BasketOrderRightsOfAccumulationAmount] = UNSET
    r"""The amount of the ROA. This is a monetary value in the same currency as the order. Only 9,999,999.99 is supported."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = ["amount"]
        nullable_fields = ["amount"]
        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 BasketOrderSide(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The side of this order."""

    SIDE_UNSPECIFIED = "SIDE_UNSPECIFIED"
    BUY = "BUY"
    SELL = "SELL"


class BasketOrderTimeInForce(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""Must be the value \"DAY\". Regulatory requirements dictate that the system capture the intended time_in_force, which is why this a mandatory field."""

    TIME_IN_FORCE_UNSPECIFIED = "TIME_IN_FORCE_UNSPECIFIED"
    DAY = "DAY"


class BasketOrderTypedDict(TypedDict):
    r"""The message describing an order that has been added to a basket"""

    account_id: NotRequired[str]
    r"""The identifier of the account transacting this order"""
    asset_id: NotRequired[str]
    r"""Apex Asset ID for this asset. This will not be returned in the initial CreateOrder response and will be available after an order completes validation. If the provided identifier does not match any Apex asset available for trading, an OrderRejectReason of \"UNKNOWN_SECURITY\" will be returned and the asset_id will not be set."""
    asset_type: NotRequired[BasketOrderAssetType]
    r"""The type of the asset in this order"""
    average_prices: NotRequired[List[ExecutedPriceTypedDict]]
    r"""The average prices, as weighted averages, across all executions in this order. Will be absent if an order has no executions.

    When asset_type = EQUITY, there will be at most one value present, with a type of PRICE_PER_UNIT. This will have up to 4 decimal places for USD amounts less than $1, and a maximum of two for larger USD amounts.
    """
    basket_order_id: NotRequired[str]
    r"""System generated unique id for the basket order."""
    client_order_id: NotRequired[str]
    r"""User-supplied unique order ID. Cannot be more than 40 characters long."""
    client_order_received_time: NotRequired[Nullable[datetime]]
    r"""Time the order request was received by the client"""
    create_time: NotRequired[Nullable[datetime]]
    r"""Time of the order creation"""
    cumulative_notional_value: NotRequired[
        Nullable[BasketOrderCumulativeNotionalValueTypedDict]
    ]
    r"""The product of order quantity & price, summed across all fills, reported in the currency specified in the order. (This will be rounded to 2 decimal places for USD currencies). Will be absent if an order has no fill information."""
    currency_code: NotRequired[str]
    r"""Defaults to \"USD\". Only \"USD\" is supported. Full list of currency codes is defined at: https://en.wikipedia.org/wiki/ISO_4217"""
    fees: NotRequired[List[FeeTypedDict]]
    r"""Fees that will be applied to this order."""
    filled_quantity: NotRequired[Nullable[BasketOrderFilledQuantityTypedDict]]
    r"""The summed quantity value across all fills in this order, up to a maximum of 5 decimal places. Will be absent if an order has no fill information."""
    identifier: NotRequired[str]
    r"""Identifier of the asset (of the type specified in `identifier_type`)."""
    identifier_type: NotRequired[BasketOrderIdentifierType]
    r"""The identifier type of the asset being ordered. For Equities: only SYMBOL is supported For Mutual Funds: only SYMBOL and CUSIP are supported"""
    last_update_time: NotRequired[Nullable[datetime]]
    r"""Time of the last order update"""
    letter_of_intent: NotRequired[Nullable[BasketOrderLetterOfIntentTypedDict]]
    r"""Letter of Intent (LOI). An LOI allows investors to receive sales charge discounts based on a commitment to buy a specified monetary amount of shares over a period of time, usually 13 months. Either ROA or LOI may be specified, but not both."""
    name: NotRequired[str]
    r"""System generated name of the basket order."""
    notional_value: NotRequired[Nullable[BasketOrderNotionalValueTypedDict]]
    r"""Notional quantity of the order, measured in USD. Maximum 2 decimal place precision. Either a quantity or notional_value MUST be specified (but not both). For Equities: currently not supported yet For Mutual Funds: Only supported for BUY orders. The order will be transacted at the full notional amount specified."""
    order_rejected_reason: NotRequired[BasketOrderOrderRejectedReason]
    r"""When an order has the REJECTED status, this will be populated with a system code describing the rejection."""
    order_status: NotRequired[BasketOrderOrderStatus]
    r"""The processing status of the order"""
    order_type: NotRequired[BasketOrderOrderType]
    r"""The execution type of this order."""
    quantity: NotRequired[Nullable[BasketOrderQuantityTypedDict]]
    r"""Numeric quantity of the order. Either a quantity or notional_value MUST be specified (but not both). For Equities: Represents the number of shares, must be greater than zero and may not exceed 5 decimal places. For Mutual Funds: Only supported for SELL orders. Represents the number of shares, up to a maximum of 3 decimal places."""
    rights_of_accumulation: NotRequired[
        Nullable[BasketOrderRightsOfAccumulationTypedDict]
    ]
    r"""Rights of Accumulation (ROA). An ROA allows an investor to aggregate their own fund shares with the holdings of certain related parties toward achieving the investment thresholds at which sales charge discounts become available. Either ROA or LOI may be specified, but not both."""
    side: NotRequired[BasketOrderSide]
    r"""The side of this order."""
    time_in_force: NotRequired[BasketOrderTimeInForce]
    r"""Must be the value \"DAY\". Regulatory requirements dictate that the system capture the intended time_in_force, which is why this a mandatory field."""


class BasketOrder(BaseModel):
    r"""The message describing an order that has been added to a basket"""

    account_id: Optional[str] = None
    r"""The identifier of the account transacting this order"""

    asset_id: Optional[str] = None
    r"""Apex Asset ID for this asset. This will not be returned in the initial CreateOrder response and will be available after an order completes validation. If the provided identifier does not match any Apex asset available for trading, an OrderRejectReason of \"UNKNOWN_SECURITY\" will be returned and the asset_id will not be set."""

    asset_type: Annotated[
        Optional[BasketOrderAssetType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The type of the asset in this order"""

    average_prices: Optional[List[ExecutedPrice]] = None
    r"""The average prices, as weighted averages, across all executions in this order. Will be absent if an order has no executions.

    When asset_type = EQUITY, there will be at most one value present, with a type of PRICE_PER_UNIT. This will have up to 4 decimal places for USD amounts less than $1, and a maximum of two for larger USD amounts.
    """

    basket_order_id: Optional[str] = None
    r"""System generated unique id for the basket order."""

    client_order_id: Optional[str] = None
    r"""User-supplied unique order ID. Cannot be more than 40 characters long."""

    client_order_received_time: OptionalNullable[datetime] = UNSET
    r"""Time the order request was received by the client"""

    create_time: OptionalNullable[datetime] = UNSET
    r"""Time of the order creation"""

    cumulative_notional_value: OptionalNullable[
        BasketOrderCumulativeNotionalValue
    ] = UNSET
    r"""The product of order quantity & price, summed across all fills, reported in the currency specified in the order. (This will be rounded to 2 decimal places for USD currencies). Will be absent if an order has no fill information."""

    currency_code: Optional[str] = None
    r"""Defaults to \"USD\". Only \"USD\" is supported. Full list of currency codes is defined at: https://en.wikipedia.org/wiki/ISO_4217"""

    fees: Optional[List[Fee]] = None
    r"""Fees that will be applied to this order."""

    filled_quantity: OptionalNullable[BasketOrderFilledQuantity] = UNSET
    r"""The summed quantity value across all fills in this order, up to a maximum of 5 decimal places. Will be absent if an order has no fill information."""

    identifier: Optional[str] = None
    r"""Identifier of the asset (of the type specified in `identifier_type`)."""

    identifier_type: Optional[BasketOrderIdentifierType] = None
    r"""The identifier type of the asset being ordered. For Equities: only SYMBOL is supported For Mutual Funds: only SYMBOL and CUSIP are supported"""

    last_update_time: OptionalNullable[datetime] = UNSET
    r"""Time of the last order update"""

    letter_of_intent: OptionalNullable[BasketOrderLetterOfIntent] = UNSET
    r"""Letter of Intent (LOI). An LOI allows investors to receive sales charge discounts based on a commitment to buy a specified monetary amount of shares over a period of time, usually 13 months. Either ROA or LOI may be specified, but not both."""

    name: Optional[str] = None
    r"""System generated name of the basket order."""

    notional_value: OptionalNullable[BasketOrderNotionalValue] = UNSET
    r"""Notional quantity of the order, measured in USD. Maximum 2 decimal place precision. Either a quantity or notional_value MUST be specified (but not both). For Equities: currently not supported yet For Mutual Funds: Only supported for BUY orders. The order will be transacted at the full notional amount specified."""

    order_rejected_reason: Annotated[
        Optional[BasketOrderOrderRejectedReason],
        PlainValidator(validate_open_enum(False)),
    ] = None
    r"""When an order has the REJECTED status, this will be populated with a system code describing the rejection."""

    order_status: Annotated[
        Optional[BasketOrderOrderStatus], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The processing status of the order"""

    order_type: Annotated[
        Optional[BasketOrderOrderType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The execution type of this order."""

    quantity: OptionalNullable[BasketOrderQuantity] = UNSET
    r"""Numeric quantity of the order. Either a quantity or notional_value MUST be specified (but not both). For Equities: Represents the number of shares, must be greater than zero and may not exceed 5 decimal places. For Mutual Funds: Only supported for SELL orders. Represents the number of shares, up to a maximum of 3 decimal places."""

    rights_of_accumulation: OptionalNullable[BasketOrderRightsOfAccumulation] = UNSET
    r"""Rights of Accumulation (ROA). An ROA allows an investor to aggregate their own fund shares with the holdings of certain related parties toward achieving the investment thresholds at which sales charge discounts become available. Either ROA or LOI may be specified, but not both."""

    side: Annotated[
        Optional[BasketOrderSide], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The side of this order."""

    time_in_force: Annotated[
        Optional[BasketOrderTimeInForce], PlainValidator(validate_open_enum(False))
    ] = None
    r"""Must be the value \"DAY\". Regulatory requirements dictate that the system capture the intended time_in_force, which is why this a mandatory field."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "account_id",
            "asset_id",
            "asset_type",
            "average_prices",
            "basket_order_id",
            "client_order_id",
            "client_order_received_time",
            "create_time",
            "cumulative_notional_value",
            "currency_code",
            "fees",
            "filled_quantity",
            "identifier",
            "identifier_type",
            "last_update_time",
            "letter_of_intent",
            "name",
            "notional_value",
            "order_rejected_reason",
            "order_status",
            "order_type",
            "quantity",
            "rights_of_accumulation",
            "side",
            "time_in_force",
        ]
        nullable_fields = [
            "client_order_received_time",
            "create_time",
            "cumulative_notional_value",
            "filled_quantity",
            "last_update_time",
            "letter_of_intent",
            "notional_value",
            "quantity",
            "rights_of_accumulation",
        ]
        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
