import datetime
from typing import Optional, Union
from .base import (
AmericanOptionExercise,
EuropeanOptionExercise,
ExerciseDatetime,
ForwardExercise,
OptionExercise,
Security,
SecurityReference,
)
from .constructors import create_reference_from_security
from .enums import (
ExpirySeriesType,
ExpiryTimeOfDay,
OptionExerciseStyle,
OptionFlavor,
SecuritySubtype,
SecurityType,
SettlementType,
)
from .exceptions import InvalidSettlementType, UnknownDenominatedCurrency
[docs]def is_physical_settlement_available(security: Security) -> bool:
# security_type = security.security_type
security_subtype = security.security_subtype
if security_subtype in (
SecuritySubtype.DERIVED_INDEX,
SecuritySubtype.TERM_RATE,
SecuritySubtype.OVERNIGHT_RATE,
SecuritySubtype.UNKNOWN,
):
return False
else:
return True
[docs]def get_flavor(callput: Union[str, OptionFlavor]) -> OptionFlavor:
if isinstance(callput, OptionFlavor):
flavor = callput
elif isinstance(callput, str):
good_callput = callput.strip().lower()
if good_callput == "call":
flavor = OptionFlavor.CALL
elif good_callput == "put":
flavor = OptionFlavor.PUT
else:
raise ValueError("Unknown callput type: {0}".format(callput))
return flavor
[docs]def get_settlement_type(
underlyer: Security, settlement_type: Optional[SettlementType]
) -> SettlementType:
"""Returns the implied settlement type available for a given underlyer and specified type."""
if is_physical_settlement_available(underlyer):
if settlement_type is None or settlement_type == SettlementType.UNKNOWN:
raise InvalidSettlementType(
"Must specify settlement type, since underlying permits physical delivery"
)
else:
if settlement_type == SettlementType.PHYSICAL:
raise InvalidSettlementType("Cannot physically-settle a derived index")
else:
settlement_type = SettlementType.CASH
return settlement_type
[docs]def get_future_exercise(
expiry_date: Union[datetime.date, datetime.datetime, str],
settlement_type: SettlementType,
expiry_time_of_day: ExpiryTimeOfDay = ExpirySeriesType.UNKNOWN,
expiry_series_type: ExpirySeriesType = ExpirySeriesType.UNKNOWN,
) -> ForwardExercise:
"""Returns the exercise object from supplied info."""
if isinstance(expiry_date, str):
expiry_date = datetime.datetime.strptime(expiry_date, "%Y-%m-%d").date()
expiry_datetime = None
elif isinstance(expiry_date, datetime.datetime):
expiry_datetime = expiry_date
expiry_date = expiry_date.date()
elif isinstance(expiry_date, datetime.date):
expiry_date = expiry_date
expiry_datetime = None
exercise = ExerciseDatetime(
expiry_date=expiry_date,
expiry_datetime=expiry_datetime,
expiry_time_of_day=expiry_time_of_day,
expiry_series_type=expiry_series_type,
settlement_type=settlement_type,
)
res = ForwardExercise(exercise=exercise)
return res
[docs]def get_option_exercise(
expiry_date: Union[datetime.date, datetime.datetime, str],
style: OptionExerciseStyle,
settlement_type: SettlementType,
expiry_time_of_day: ExpiryTimeOfDay = ExpirySeriesType.UNKNOWN,
expiry_series_type: ExpirySeriesType = ExpirySeriesType.UNKNOWN,
) -> OptionExercise:
"""Returns the exercise object from supplied info."""
if isinstance(expiry_date, str):
expiry_date = datetime.datetime.strptime(expiry_date, "%Y-%m-%d").date()
expiry_datetime = None
elif isinstance(expiry_date, datetime.datetime):
expiry_datetime = expiry_date
expiry_date = expiry_date.date()
elif isinstance(expiry_date, datetime.date):
expiry_date = expiry_date
expiry_datetime = None
exercise = ExerciseDatetime(
expiry_date=expiry_date,
expiry_datetime=expiry_datetime,
expiry_time_of_day=expiry_time_of_day,
expiry_series_type=expiry_series_type,
settlement_type=settlement_type,
)
if style == OptionExerciseStyle.AMERICAN:
res = AmericanOptionExercise(style=style, exercise=exercise)
elif style == OptionExerciseStyle.EUROPEAN:
res = EuropeanOptionExercise(style=style, exercise=exercise)
return res
[docs]def determine_option_subtype(
underlying_security: Security, currency: Security
) -> SecuritySubtype:
"""Returns the option subtype implied from underlyer and supplied currency."""
lookup = {
(SecurityType.INDEX, SecurityType.CURRENCY): SecuritySubtype.INDEX_OPTION,
(SecurityType.EQUITY, SecurityType.CURRENCY): SecuritySubtype.EQUITY_OPTION,
(SecurityType.CURRENCY, SecurityType.CURRENCY): SecuritySubtype.CURRENCY_OPTION,
}
return lookup[(underlying_security.security_type, currency.security_type)]
[docs]def get_deriv_currency(
underlying_security: Security, currency: Optional[Security] = None
) -> SecurityReference:
"""Returns the derivative currency implied from underlyer and supplied currency."""
if currency is None:
if underlying_security.denominated_ccy is None:
raise UnknownDenominatedCurrency(
"Must declare denominated currency, if not supplied by underlier"
)
else:
currency = underlying_security.denominated_ccy
elif isinstance(currency, Security):
currency = create_reference_from_security(currency)
return currency