primo commit
This commit is contained in:
560
pricer/payoffs.py
Normal file
560
pricer/payoffs.py
Normal file
@@ -0,0 +1,560 @@
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
class PayoffEvaluator:
|
||||
def evaluate(self, path: List[List[float]], context: "PayoffContext") -> float:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@dataclass
|
||||
class PayoffContext:
|
||||
days_to_maturity: int
|
||||
r: float
|
||||
capital_value: float
|
||||
prot_min_val: float
|
||||
pdi_barrier: float
|
||||
pdi_style: str
|
||||
coupon_in_memory: float
|
||||
days_to_obs_y_fract: List[float]
|
||||
coupon_triggers: List[float]
|
||||
coupon_values: List[float]
|
||||
autocall_triggers: List[float]
|
||||
autocall_values: List[float]
|
||||
memory_flags: List[int]
|
||||
caso: str
|
||||
pdi_strike: float
|
||||
fattore_airbag: float
|
||||
trigger_one_star: float
|
||||
cap: float
|
||||
days_to_obs: List[int]
|
||||
volatility: List[float]
|
||||
airbag: int
|
||||
sigma: int
|
||||
relief: int
|
||||
twin_win: int
|
||||
one_star: int
|
||||
leva: float
|
||||
nominal_amount: float
|
||||
prices_ul: List[float]
|
||||
|
||||
|
||||
class PayoffFactory:
|
||||
@staticmethod
|
||||
def get_evaluator(caso: str) -> PayoffEvaluator:
|
||||
mapping = {
|
||||
"Standard": PayoffStandard(),
|
||||
"Airbag": PayoffAirbag(),
|
||||
"Sigma": PayoffSigma(),
|
||||
"Relief": PayoffRelief(),
|
||||
"TwinWin": PayoffTwinWin(),
|
||||
"OneStar": PayoffOneStar(),
|
||||
"Airbag + OneStar": PayoffAirbagOneStar(),
|
||||
"Sigma + OneStar": PayoffSigmaOneStar(),
|
||||
"Relief + OneStar": PayoffReliefOneStar(),
|
||||
"TwinWin + OneStar": PayoffTwinWinOneStar(),
|
||||
"Airbag + TwinWin": PayoffAirbagTwinWin(),
|
||||
}
|
||||
if caso not in mapping:
|
||||
raise ValueError(f"Payoff '{caso}' non gestito.")
|
||||
return mapping[caso]
|
||||
|
||||
|
||||
def _row_min(path, index: int) -> float:
|
||||
if isinstance(path, np.ndarray):
|
||||
return float(path[index].min())
|
||||
return min(path[index])
|
||||
|
||||
|
||||
def _row_max(path, index: int) -> float:
|
||||
if isinstance(path, np.ndarray):
|
||||
return float(path[index].max())
|
||||
return max(path[index])
|
||||
|
||||
|
||||
def _overall_min(path) -> float:
|
||||
if isinstance(path, np.ndarray):
|
||||
return float(path.min())
|
||||
return _overall_min(path)
|
||||
|
||||
class PayoffStandard(PayoffEvaluator):
|
||||
def __init__(self):
|
||||
self.last_label = ""
|
||||
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
payoff = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
payoff = (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
self.last_label = (
|
||||
f"Autocall ? Trigger={c.autocall_triggers[k]:.2f}, Min={min_val:.2f} ? Payoff={payoff:.2f}"
|
||||
)
|
||||
return payoff
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
barrier_check = min_mat if c.pdi_style == "European" else min_total
|
||||
|
||||
if barrier_check >= c.pdi_barrier:
|
||||
payoff = (c.capital_value + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
self.last_label = (
|
||||
f"RIMBORSO standard ? minMat={min_mat:.4f}, minTotal={min_total:.4f} ? Payoff={payoff:.2f}"
|
||||
)
|
||||
else:
|
||||
payoff = max(c.prot_min_val, min_mat / 100.0) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
self.last_label = (
|
||||
f"PERDITA standard ? minMat={min_mat:.4f}, minTotal={min_total:.4f} ? Payoff={payoff:.2f}"
|
||||
)
|
||||
|
||||
return payoff
|
||||
|
||||
self.last_label = "UNKNOWN"
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffAirbag(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_barriera:
|
||||
payoff = c.capital_value + memory
|
||||
else:
|
||||
payoff = max(c.prot_min_val, (min_mat * c.fattore_airbag / 100.0))
|
||||
|
||||
return payoff * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffTwinWin(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_strike = min_mat >= c.pdi_strike and c.autocall_triggers[k] == 999
|
||||
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_strike:
|
||||
payoff = memory + min(min_mat / 100.0, c.cap)
|
||||
elif sopra_barriera:
|
||||
payoff = (200.0 - min_mat) * c.capital_value / 100.0 + memory
|
||||
else:
|
||||
payoff = max(c.prot_min_val, min_mat / 100.0) + memory
|
||||
|
||||
return payoff * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffOneStar(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
max_mat = _row_max(path, c.days_to_obs[k])
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_trigger = max_mat >= c.trigger_one_star
|
||||
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
capitale = c.capital_value if (sopra_trigger or sopra_barriera) else max(c.prot_min_val, min_mat / 100.0)
|
||||
|
||||
cedola_finale = 0.0
|
||||
if min_mat >= c.coupon_triggers[k]:
|
||||
cedola_finale = memory + c.coupon_values[k]
|
||||
|
||||
return (
|
||||
capitale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ cedola_finale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ coupons
|
||||
)
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffSigma(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_barriera:
|
||||
payoff = c.capital_value + memory
|
||||
else:
|
||||
payoff = max(c.prot_min_val, (min_mat + c.pdi_strike - c.pdi_barrier) / 100.0)
|
||||
|
||||
return payoff * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffRelief(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
prices_at_mat = path[c.days_to_maturity]
|
||||
sorted_prices = sorted(prices_at_mat)
|
||||
second_min = sorted_prices[1] if len(sorted_prices) >= 2 else sorted_prices[0]
|
||||
min_mat = min(prices_at_mat)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_barriera:
|
||||
payoff = c.capital_value + memory
|
||||
else:
|
||||
payoff = max(c.prot_min_val, second_min / 100.0)
|
||||
|
||||
return payoff * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffAirbagOneStar(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
max_mat = _row_max(path, c.days_to_obs[k])
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_trigger = max_mat >= c.trigger_one_star
|
||||
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_trigger or sopra_barriera:
|
||||
capitale = c.capital_value
|
||||
else:
|
||||
perc = max(c.prot_min_val, min_mat / 100.0) * c.fattore_airbag
|
||||
capitale = min(c.capital_value, perc)
|
||||
|
||||
cedola_finale = 0.0
|
||||
if min_mat >= c.coupon_triggers[k]:
|
||||
cedola_finale = memory + c.coupon_values[k]
|
||||
|
||||
return (
|
||||
capitale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ cedola_finale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ coupons
|
||||
)
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffSigmaOneStar(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
max_mat = _row_max(path, c.days_to_obs[k])
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_trigger = max_mat >= c.trigger_one_star
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_trigger or sopra_barriera:
|
||||
capitale = c.capital_value
|
||||
else:
|
||||
capitale = max(c.prot_min_val, (min_mat + c.pdi_strike - c.pdi_barrier) / 100.0)
|
||||
|
||||
cedola_finale = 0.0
|
||||
if min_mat >= c.coupon_triggers[k]:
|
||||
cedola_finale = memory + c.coupon_values[k]
|
||||
|
||||
return (
|
||||
capitale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ cedola_finale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ coupons
|
||||
)
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffReliefOneStar(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
prices_at_mat = path[c.days_to_maturity]
|
||||
sorted_prices = sorted(prices_at_mat)
|
||||
second_min = sorted_prices[1] if len(sorted_prices) >= 2 else sorted_prices[0]
|
||||
min_mat = min(prices_at_mat)
|
||||
max_mat = _row_max(path, c.days_to_obs[k])
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_trigger = max_mat >= c.trigger_one_star
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_trigger or sopra_barriera:
|
||||
capitale = c.capital_value
|
||||
else:
|
||||
capitale = max(c.prot_min_val, second_min / 100.0)
|
||||
|
||||
cedola_finale = 0.0
|
||||
if min_mat >= c.coupon_triggers[k]:
|
||||
cedola_finale = memory + c.coupon_values[k]
|
||||
|
||||
return (
|
||||
capitale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ cedola_finale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ coupons
|
||||
)
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffTwinWinOneStar(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
max_mat = _row_max(path, c.days_to_obs[k])
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
min_total = _overall_min(path)
|
||||
|
||||
sopra_strike = min_mat >= c.pdi_strike
|
||||
sopra_barriera = (
|
||||
(c.pdi_style == "European" and min_mat >= c.pdi_barrier)
|
||||
or (c.pdi_style == "American" and min_total >= c.pdi_barrier)
|
||||
)
|
||||
|
||||
if sopra_strike:
|
||||
capitale = min(min_mat / 100.0, c.cap)
|
||||
elif sopra_barriera:
|
||||
capitale = (2 * c.capital_value) - (min_mat / 100.0)
|
||||
else:
|
||||
if max_mat >= c.trigger_one_star:
|
||||
capitale = c.capital_value
|
||||
else:
|
||||
capitale = max(c.prot_min_val, min_mat / 100.0)
|
||||
|
||||
cedola_finale = 0.0
|
||||
if min_mat >= c.coupon_triggers[k]:
|
||||
cedola_finale = memory + c.coupon_values[k]
|
||||
|
||||
return (
|
||||
capitale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ cedola_finale * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
+ coupons
|
||||
)
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
class PayoffAirbagTwinWin(PayoffEvaluator):
|
||||
def evaluate(self, path: List[List[float]], c: PayoffContext) -> float:
|
||||
memory = c.coupon_in_memory
|
||||
coupons = 0.0
|
||||
|
||||
for k in range(len(c.days_to_obs)):
|
||||
min_val = _row_min(path, c.days_to_obs[k])
|
||||
|
||||
if min_val >= c.autocall_triggers[k]:
|
||||
return (c.autocall_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k]) + coupons
|
||||
|
||||
if min_val >= c.coupon_triggers[k]:
|
||||
coupons += (c.coupon_values[k] + memory) * math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
memory = 0.0
|
||||
else:
|
||||
memory += c.memory_flags[k] * c.coupon_values[k]
|
||||
|
||||
if k == len(c.days_to_obs) - 1:
|
||||
min_mat = _row_min(path, c.days_to_maturity)
|
||||
|
||||
if min_mat >= c.pdi_barrier:
|
||||
if c.autocall_triggers[k] == 999 and min_mat >= c.pdi_strike:
|
||||
return (
|
||||
math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
* (memory + min(min_mat / 100.0, c.cap))
|
||||
+ coupons
|
||||
)
|
||||
return (
|
||||
math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
* ((2 * c.capital_value) + memory - (min_mat / 100.0))
|
||||
+ coupons
|
||||
)
|
||||
|
||||
return (
|
||||
max(c.prot_min_val, min_mat / 100.0)
|
||||
* math.exp(-c.r * c.days_to_obs_y_fract[k])
|
||||
* c.fattore_airbag
|
||||
+ coupons
|
||||
)
|
||||
|
||||
return 0.0
|
||||
|
||||
Reference in New Issue
Block a user