Skip to content

Commit

Permalink
refactor equity option and added volterm structure
Browse files Browse the repository at this point in the history
  • Loading branch information
siddharthqs committed Oct 23, 2023
1 parent 9664b01 commit 8656f07
Show file tree
Hide file tree
Showing 14 changed files with 272 additions and 77 deletions.
10 changes: 10 additions & 0 deletions derivatives/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file removed derivatives/build/derivatives.exe
Binary file not shown.
7 changes: 5 additions & 2 deletions derivatives/src/core/quotes.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
pub struct Quote{
pub value: f64
pub value: f64,
pub bid: f64,
pub ask: f64,
pub mid: f64,
}
impl Quote{
pub fn new(value: f64) -> Self {
Quote{value: value}
Quote{value: value, bid: value, ask: value, mid: value }
}
pub fn value(&self) -> f64 { self.value }
pub fn valid_value(&self) -> bool { self.value>0.0}
Expand Down
4 changes: 3 additions & 1 deletion derivatives/src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ pub struct MarketData {
pub underlying_price:f64,
pub option_type:String,
pub strike_price:f64,
pub volatility:f64,
pub volatility:Option<f64>,
pub option_price:Option<f64>,
pub risk_free_rate:Option<f64>,
pub maturity:String,
pub dividend: Option<f64>,
Expand Down Expand Up @@ -73,6 +74,7 @@ pub struct CombinedContract{

#[derive(Debug, Deserialize,Serialize)]
pub struct Contracts {
pub asset: String,
pub contracts: Vec<Contract>,
}
#[derive(Debug, Deserialize,Serialize)]
Expand Down
19 changes: 10 additions & 9 deletions derivatives/src/equity/blackscholes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,20 @@ use super::super::core::termstructure::YieldTermStructure;
use super::super::core::traits::{Instrument,Greeks};
use super::super::core::interpolation;


pub fn npv(bsd_option: &&EquityOption) -> f64 {
assert!(bsd_option.volatility >= 0.0);
assert!(bsd_option.time_to_maturity >= 0.0);
assert!(bsd_option.current_price.value >= 0.0);
assert!(bsd_option.underlying_price.value >= 0.0);
if bsd_option.option_type == OptionType::Call {
let option_price = bsd_option.current_price.value()
let option_price = bsd_option.underlying_price.value()
* N(bsd_option.d1())
* exp(-bsd_option.dividend_yield * bsd_option.time_to_maturity)
- bsd_option.strike_price
* exp(-bsd_option.risk_free_rate * bsd_option.time_to_maturity)
* N(bsd_option.d2());
return option_price;
} else {
let option_price = -bsd_option.current_price.value()
let option_price = -bsd_option.underlying_price.value()
* N(-bsd_option.d1())
* exp(-bsd_option.dividend_yield * bsd_option.time_to_maturity)
+ bsd_option.strike_price
Expand Down Expand Up @@ -194,11 +193,12 @@ pub fn option_pricing() {
let date = vec![0.01,0.02,0.05,0.1,0.5,1.0,2.0,3.0];
let rates = vec![0.05,0.05,0.06,0.07,0.08,0.9,0.9,0.10];
let ts = YieldTermStructure::new(date,rates);
let curr_quote = Quote{value: curr_price.trim().parse::<f64>().unwrap()};
let curr_quote = Quote::new( curr_price.trim().parse::<f64>().unwrap());
let mut option = EquityOption {
option_type: side,
transection: Transection::Buy,
current_price: curr_quote,
underlying_price: curr_quote,
current_price: Quote::new(0.0),
strike_price: strike.trim().parse::<f64>().unwrap(),
volatility: vol.trim().parse::<f64>().unwrap(),
time_to_maturity: expiry.trim().parse::<f64>().unwrap(),
Expand Down Expand Up @@ -279,12 +279,13 @@ pub fn implied_volatility() {
let date = vec![0.01,0.02,0.05,0.1,0.5,1.0,2.0,3.0];
let rates = vec![0.01,0.02,0.05,0.07,0.08,0.1,0.11,0.12];
let ts = YieldTermStructure::new(date,rates);
let curr_quote = Quote{value: curr_price.trim().parse::<f64>().unwrap()};
let sim = std::option::Option::Some(10000);
let curr_quote = Quote::new( curr_price.trim().parse::<f64>().unwrap());
let sim = Some(10000);
let mut option = EquityOption {
option_type: side,
transection: Transection::Buy,
current_price: curr_quote,
underlying_price: curr_quote,
current_price: Quote::new(0.0),
strike_price: strike.trim().parse::<f64>().unwrap(),
volatility: 0.20,
time_to_maturity: expiry.trim().parse::<f64>().unwrap(),
Expand Down
109 changes: 109 additions & 0 deletions derivatives/src/equity/build_contracts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//use crate::rates;
//use crate::rates::deposits::Deposit;

use chrono::{NaiveDate,Local,Weekday};
use chrono::Datelike;
use crate::core::trade;
use super::vanila_option::{EquityOption};
use super::super::core::termstructure::YieldTermStructure;
use crate::rates::utils::TermStructure;
use crate::equity::vol_surface::VolSurface;
use crate::rates::utils::{DayCountConvention};
use crate::core::quotes::Quote;
use crate::core::utils::{Contract,ContractStyle};
use crate::equity::utils::{Engine};
use std::collections::HashMap;
pub fn build_eq_contracts(data: Contract)-> Box<EquityOption>{
let market_data = data.market_data.clone().unwrap();
let underlying_quote = Quote::new( market_data.underlying_price);
let date = vec![0.01,0.02,0.05,0.1,0.5,1.0,2.0,3.0];
let rates = vec![0.01,0.02,0.05,0.07,0.08,0.1,0.11,0.12];
let ts = YieldTermStructure::new(date,rates);
let option_type = &market_data.option_type;
let side: trade::OptionType;
match option_type.trim() {
"C" | "c" | "Call" | "call" => side = trade::OptionType::Call,
"P" | "p" | "Put" | "put" => side = trade::OptionType::Put,
_ => panic!("Invalide side argument! Side has to be either 'C' or 'P'."),
}
let maturity_date = &market_data.maturity;
let today = Local::today();
let future_date = NaiveDate::parse_from_str(&maturity_date, "%Y-%m-%d").expect("Invalid date format");
let duration = future_date.signed_duration_since(today.naive_utc());
let year_fraction = duration.num_days() as f64 / 365.0;
let rf = Some(market_data.risk_free_rate).unwrap();
let div = Some(market_data.dividend).unwrap();
let price = Some(market_data.option_price).unwrap();
let option_price = Quote::new(price.unwrap());
let mut option = EquityOption {
option_type: side,
transection: trade::Transection::Buy,
underlying_price: underlying_quote,
current_price: option_price,
strike_price: market_data.strike_price,
volatility: 0.2,
time_to_maturity: year_fraction,
risk_free_rate: rf.unwrap_or(0.0),
dividend_yield: div.unwrap_or(0.0),
transection_price: 0.0,
term_structure: ts,
engine: Engine::BlackScholes,
simulation: None,
style: ContractStyle::European,
//style: Option::from(data.style.as_ref().unwrap_or(&default_style)).map(|x| &**x),
};
match data.pricer.trim() {
"Analytical" |"analytical" => {
option.engine = Engine::BlackScholes;
}
"MonteCarlo" |"montecarlo"|"MC" => {
option.engine = Engine::MonteCarlo;
}
"Binomial"|"binomial" => {
option.engine = Engine::Binomial;
}
_ => {
panic!("Invalid pricer");}
}
match data.style.as_ref().unwrap_or(&"European".to_string()).trim() {
"European" |"european" => {
option.style = ContractStyle::European;
}
"American" |"american" => {
option.style = ContractStyle::American;
}
_ => {
option.style = ContractStyle::European;}
}
option.set_risk_free_rate();
option.volatility = option.imp_vol(option.current_price.value);
return Box::new(option);
}

pub fn build_eq_contracts_from_json(data: Vec<Contract>) -> Vec<Box<EquityOption>> {
let mut derivatives:Vec<Box<EquityOption>> = Vec::new();
for contract in data {
let eq = build_eq_contracts(contract);
derivatives.push(eq);
}
return derivatives;
}
pub fn build_vol_surface(mut contracts:Vec<Box<EquityOption>>) -> VolSurface {
//let mut ts:rates::utils::TermStructure = rates::utils::TermStructure::new(vec![],vec![],vec![],
// rates::utils::DayCountConvention::Act360);
// let mut vol_surface:VolSurface = VolSurface::new(Default::default(), 0.0, spot_date: NaiveDate::from_ymd(, 2020),
// DayCountConvention::Act365);
let mut hash_map:HashMap<NaiveDate,Vec<(f64,f64)>> = HashMap::new();
let spot_date = Local::today();
let spot_price = contracts[0].underlying_price.value;
for i in 0..contracts.len(){
let mut contract = contracts[i].as_mut();
let stike = contract.underlying_price.value / contract.strike_price as f64;
let vol = contract.volatility;
let maturity = contract.time_to_maturity;
hash_map.entry(maturity).or_insert(Vec::new()).push((stike,vol));
}
let vol_surface:VolSurface = VolSurface::new(hash_map, spot_price, spot_date,
DayCountConvention::Act365);
return vol_surface;
}
2 changes: 2 additions & 0 deletions derivatives/src/equity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ pub mod montecarlo;
pub mod forward_start_option;
pub mod utils;
pub mod binomial;
pub mod build_contracts;
pub mod vol_surface;
9 changes: 5 additions & 4 deletions derivatives/src/equity/montecarlo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub fn simulate_market(option: &&EquityOption) -> Vec<f64>{

let mut market_at_maturity:Vec<f64> = Vec::new();
for z in path{
let sim_value = option.current_price.value()
let sim_value = option.underlying_price.value()
*exp(((option.risk_free_rate - option.dividend_yield - 0.5 * option.volatility.powi(2))
* option.time_to_maturity)+option.volatility * option.time_to_maturity.sqrt()*z);
market_at_maturity.push(sim_value);
Expand Down Expand Up @@ -90,7 +90,7 @@ pub fn payoff(market: &Vec<f64>,
pub fn npv(option: &&EquityOption,path_size: bool) -> f64 {
assert!(option.volatility >= 0.0);
assert!(option.time_to_maturity >= 0.0);
assert!(option.current_price.value >= 0.0);
assert!(option.underlying_price.value >= 0.0);
let mut st = vec![];
if path_size {
st = simulate_market_path_wise(&option);
Expand Down Expand Up @@ -166,11 +166,12 @@ pub fn option_pricing() {
let date = vec![0.01,0.02,0.05,0.1,0.5,1.0,2.0,3.0];
let rates = vec![0.01,0.02,0.05,0.07,0.08,0.1,0.11,0.12];
let ts = YieldTermStructure::new(date,rates);
let curr_quote = Quote{value: curr_price.trim().parse::<f64>().unwrap()};
let curr_quote = Quote::new( curr_price.trim().parse::<f64>().unwrap());
let mut option = EquityOption {
option_type: side,
transection: Transection::Buy,
current_price: curr_quote,
underlying_price: curr_quote,
current_price: Quote::new(0.01),
strike_price: strike.trim().parse::<f64>().unwrap(),
volatility: vol.trim().parse::<f64>().unwrap(),
time_to_maturity: expiry.trim().parse::<f64>().unwrap(),
Expand Down
10 changes: 9 additions & 1 deletion derivatives/src/equity/vanila_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,23 @@ impl Instrument for EquityOption {
pub struct EquityOption {
pub option_type: OptionType,
pub transection: Transection,
pub underlying_price: Quote,
pub current_price: Quote,
pub strike_price: f64,
pub dividend_yield: f64,
pub volatility: f64,
pub time_to_maturity: f64,
pub maturity_date: NaiveDate,
pub valuation_date: NaiveDate,
pub term_structure: YieldTermStructure<f64>,
pub risk_free_rate: f64,
pub transection_price: f64,
pub engine: Engine,
pub simulation:Option<u64>,
pub style: ContractStyle,
}
impl EquityOption{
pub fn time_to_maturity(&self) -> f64{
let time_to_maturity = (self.maturity_date - self.valuation_date).num_days() as f64/365.0;
time_to_maturity
}
}
28 changes: 28 additions & 0 deletions derivatives/src/equity/vol_surface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use std::collections::HashMap;
use crate::rates::utils::{DayCountConvention};
use chrono::{NaiveDate};
#[derive(Clone,Debug)]
pub struct VolSurface{
pub term_structure: HashMap<NaiveDate, Vec<(f64,f64)>>,
pub spot: f64,
pub spot_date: NaiveDate,
pub day_count: DayCountConvention,
}

impl VolSurface {
pub fn new(term_structure: HashMap<NaiveDate, Vec<(f64,f64)>>,spot:f64,spot_date:NaiveDate,day_count:DayCountConvention) -> VolSurface {
VolSurface {
term_structure,
spot,
spot_date,
day_count
}
}
pub fn get_vol(&self,val_date:NaiveDate,maturity_date:NaiveDate,strike:f64)-> f64{
0.0
}
pub fn get_year_fraction(&self,val_date:NaiveDate,maturity_date:NaiveDate) -> f64 {
self.day_count.year_fraction(val_date,maturity_date)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use chrono::Datelike;
use crate::rates::fra::FRA;
use crate::core::traits::{Instrument,Rates};
use crate::core::utils::{Contract, Contracts};
use crate::rates::utils::TermStructure;

pub fn build_ir_contracts(data: Contract) -> Box<dyn Rates> {
let rate_data = data.rate_data.clone().unwrap();
let mut start_date_str = rate_data.start_date; // Only for 0M case
Expand Down Expand Up @@ -73,4 +75,29 @@ pub fn build_ir_contracts(data: Contract) -> Box<dyn Rates> {
else {
panic!("Invalid asset");
}
}

pub fn build_ir_contracts_from_json(data: Vec<Contract>) -> Vec<Box<dyn Rates>> {
let mut irds:Vec<Box<dyn Rates>> = Vec::new();
for contract in data {
let ird = build_ir_contracts(contract);
irds.push(ird);
}
return irds;
}
pub fn build_term_structure(mut contracts:Vec<Box<dyn Rates>>) -> TermStructure {
let mut ts:rates::utils::TermStructure = rates::utils::TermStructure::new(vec![],vec![],vec![],
rates::utils::DayCountConvention::Act360);
let mut contract = contracts[0].as_mut();
ts.discount_factor.push(contract.get_maturity_discount_factor());
ts.date.push(contract.get_maturity_date());
ts.rate.push(contract.get_rate());
for i in 1..contracts.len(){
let mut contract = contracts[i].as_mut();
contract.set_term_structure(ts.clone());
ts.discount_factor.push(contract.get_maturity_discount_factor());
ts.date.push(contract.get_maturity_date());
ts.rate.push(contract.get_rate());
}
return ts
}
3 changes: 2 additions & 1 deletion derivatives/src/rates/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod deposits;
pub(crate) mod utils;
pub mod fra;
pub mod fra;
pub mod build_contracts;
1 change: 0 additions & 1 deletion derivatives/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ pub mod read_csv;
pub mod RNG;
pub mod stochastic_processes;
pub mod parse_json;
pub mod build_contracts;
Loading

0 comments on commit 8656f07

Please sign in to comment.