Skip to content

Commit

Permalink
fixed bug in reading date.
Browse files Browse the repository at this point in the history
  • Loading branch information
siddharthqs committed Nov 4, 2023
1 parent c01a036 commit 8787fcb
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 82 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[![Build and Tests](https://github.com/siddharthqs/RustyQLib/actions/workflows/rust.yml/badge.svg)](https://github.com/siddharthqs/RustyQLib/actions/workflows/rust.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

# RUSTYQLib :Pricing Options with Confidence using JSON
RustyQLib is a lightweight yet robust quantitative finance library designed for pricing options.
Expand Down Expand Up @@ -50,6 +51,7 @@ JSON Output Clarity
- [ ] Asian
### Instruments:
#### Equity
- [x] Equity Option
- [ ] Equity Forward Start Option
- [ ] Equity Basket
Expand All @@ -58,6 +60,15 @@ JSON Output Clarity
- [ ] Equity Asian
- [ ] Equity Rainbow
- [ ] Equity Chooser
#### Interest Rate
- [x] Deposit
- [x] FRA
- [ ] Interest Rate Swap
#### Commodities
- [x] Commodity Option
- [ ] Commodity Forward Start Option
- [ ] Commodity Barrier
- [ ] Commodity Lookback
### Pricing engines:
Expand Down
39 changes: 39 additions & 0 deletions src/core/pde/bsm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/// This is Black Scholes Merton PDE solver using finite difference method
/// $ \frac{\partial V}{\partial t} + \frac{1}{2}\sigma^2 S^2 \frac{\partial^2 V}{\partial S^2} + rS\frac{\partial V}{\partial S} - rV = 0 $
/// $ V(S,T) = max(S-K,0) $
/// $ V(0,t) = 0 $
/// $ V(S,t) \rightarrow S $ as $ S \rightarrow \infty $
///https://de.wikipedia.org/wiki/Thomas-Algorithmus
// pub fn blackscholes_pde(spot:f64,strike:f64,rate:f64,volatility:f64,time_to_maturity:f64,steps:u64,option_type:OptionType) -> f64{
// let mut grid = Grid::new(spot,strike,rate,volatility,time_to_maturity,steps,option_type);
// grid.solve();
// let value = grid.get_value();
// value
// }
// pub struct Grid {
// spot: f64,
// strike: f64,
// rate: f64,
// dividend: f64,
// //volatility:f64,
// time_to_maturity: f64,
// spot_steps: u64,
// time_steps: u64
// }
// impl Grid{
// pub fn payoff(&self,spot:f64) -> f64{
// let payoff = (spot - self.strike).max(0.0);
// payoff
// }
// pub fn build_grid(&self) -> Vec<Vec<f64>>{
// let mut grid:Array2<f64> = Array2::zeros((self.time_steps as usize,self.spot_steps as usize));
// //let mut grid = vec![vec![0.0;self.spot_steps as usize];self.time_steps as usize];
// for i in 0..self.spot_steps as usize{
// grid[0][i] = self.payoff(i as f64);
// }
// grid
// }
// }



6 changes: 3 additions & 3 deletions src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ pub struct ContractOutput {
}

pub fn dN(x: f64) -> f64 {
// Probability density function of standard normal random variable x.
/// Probability density function of standard normal random variable x.
let t = -0.5 * x * x;
return t.exp() / (SQRT_2 * PI.sqrt());
}

pub fn N(x: f64) -> f64 {
//umulative density function of standard normal random variable x.
///Cumulative density function of standard normal random variable x.
let m = probability::distribution::Gaussian::new(0.0, 1.0);
let cdf = m.distribution(x);
return cdf;
}
//}

15 changes: 12 additions & 3 deletions src/equity/blackscholes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,14 @@ impl EquityOption {
}
pub fn option_pricing() {
println!("Welcome to the Black-Scholes Option pricer.");
println!("(Step 1/7) What is the current price of the underlying asset?");
println!(" What is the current price of the underlying asset?");
print!(">>");
let mut curr_price = String::new();
io::stdin()
.read_line(&mut curr_price)
.expect("Failed to read line");
println!("(Step 2/7) Do you want a call option ('C') or a put option ('P') ?");
println!(" Do you want a call option ('C') or a put option ('P') ?");
print!(">>");
let mut side_input = String::new();
io::stdin()
.read_line(&mut side_input)
Expand All @@ -170,28 +171,36 @@ pub fn option_pricing() {
_ => panic!("Invalide side argument! Side has to be either 'C' or 'P'."),
}
println!("Stike price:");
print!(">>");
let mut strike = String::new();
io::stdin()
.read_line(&mut strike)
.expect("Failed to read line");
println!("Expected annualized volatility in %:");
println!("E.g.: Enter 50% chance as 0.50 ");
print!(">>");
let mut vol = String::new();
io::stdin()
.read_line(&mut vol)
.expect("Failed to read line");

println!("Risk-free rate in %:");
print!(">>");
let mut rf = String::new();
io::stdin().read_line(&mut rf).expect("Failed to read line");
println!(" Maturity date in YYYY-MM-DD format:");

let mut expiry = String::new();
println!("E.g.: Enter 2020-12-31 for 31st December 2020");
print!(">>");
io::stdin()
.read_line(&mut expiry)
.expect("Failed to read line");
let future_date = NaiveDate::parse_from_str(&expiry, "%Y-%m-%d").expect("Invalid date format");
println!("{:?}", expiry.trim());
let _d = expiry.trim();
let future_date = NaiveDate::parse_from_str(&_d, "%Y-%m-%d").expect("Invalid date format");
println!("Dividend yield on this stock:");
print!(">>");
let mut div = String::new();
io::stdin()
.read_line(&mut div)
Expand Down
20 changes: 2 additions & 18 deletions src/equity/build_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,7 @@ use crate::core::utils::{Contract,ContractStyle};
use crate::equity::utils::{Engine};
use std::collections::BTreeMap;

pub fn build_eq_contracts_from_json(data: Vec<Contract>) -> Vec<Box<EquityOption>> {
let derivatives:Vec<Box<EquityOption>> = data.iter().map(|x| EquityOption::from_json(x.clone())).collect();
pub fn build_eq_contracts_from_json(mut data: Vec<Contract>) -> Vec<Box<EquityOption>> {
let derivatives:Vec<Box<EquityOption>> = data.iter().map(|x| EquityOption::from_json(&x)).collect();
return derivatives;
}
pub fn build_volatility_surface(mut contracts:Vec<Box<EquityOption>>) -> VolSurface {

let mut vol_tree:BTreeMap<NaiveDate,Vec<(f64,f64)>> = BTreeMap::new();
let spot_date = contracts[0].valuation_date;
let spot_price = contracts[0].underlying_price.value;
for i in 0..contracts.len(){
let mut contract = contracts[i].as_mut();
let moneyness = contract.underlying_price.value / contract.strike_price as f64;
let volatility = contract.get_imp_vol();
let maturity = contract.maturity_date;
vol_tree.entry(maturity).or_insert(Vec::new()).push((moneyness,volatility));
}
let vol_surface:VolSurface = VolSurface::new(vol_tree, spot_price, spot_date,
DayCountConvention::Act365);
return vol_surface;
}
8 changes: 4 additions & 4 deletions src/equity/vanila_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Instrument for EquityOption {
}
}
}
/// Equity Option represents a real world equity option contract
/// This struct represents a real world equity option contract
#[derive(Debug)]
pub struct EquityOption {
pub option_type: OptionType,
Expand All @@ -59,8 +59,8 @@ impl EquityOption{
}
}
impl EquityOption {
pub fn from_json(data: Contract) -> Box<EquityOption> {
let market_data = data.market_data.unwrap();
pub fn from_json(data: &Contract) -> Box<EquityOption> {
let market_data = data.market_data.as_ref().unwrap();
let underlying_quote = Quote::new(market_data.underlying_price);
//TODO: Add term structure
let date = vec![0.01, 0.02, 0.05, 0.1, 0.5, 1.0, 2.0, 3.0];
Expand Down Expand Up @@ -168,7 +168,7 @@ mod tests {
style: Some("European".to_string()),
rate_data: None
};
let option = EquityOption::from_json(data);
let option = EquityOption::from_json(&data);
assert_eq!(option.option_type, OptionType::Call);
assert_eq!(option.transection, Transection::Buy);
assert_eq!(option.underlying_price.value, 100.0);
Expand Down
50 changes: 49 additions & 1 deletion src/equity/vol_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use crate::rates::utils::{DayCountConvention};
use chrono::{NaiveDate};
use crate::core::trade::OptionType;
use super::vanila_option::{EquityOption};

/// Vol Surface is a collection of volatilities for different maturities and strikes
#[derive(Clone,Debug,Serialize,Deserialize)]
Expand All @@ -28,5 +30,51 @@ impl VolSurface {
pub fn get_year_fraction(&self,val_date:NaiveDate,maturity_date:NaiveDate) -> f64 {
self.day_count.get_year_fraction(val_date,maturity_date)
}
pub fn build_eq_vol(mut contracts:Vec<Box<EquityOption>>) -> VolSurface {
let mut vol_tree:BTreeMap<NaiveDate,Vec<(f64,f64)>> = BTreeMap::new();
let spot_date = contracts[0].valuation_date;
let spot_price = contracts[0].underlying_price.value;
for i in 0..contracts.len(){
let mut moneyness=1.0;
let mut contract = contracts[i].as_mut();
match contract.option_type{
OptionType::Call => {
moneyness = contract.underlying_price.value / contract.strike_price as f64;

}
},
OptionType::Put => {
moneyness = contract.strike_price / contract.underlying_price.value as f64;
}
_ => {
panic!("Option type not supported");
}
}
let volatility = contract.get_imp_vol();
let maturity = contract.maturity_date;
vol_tree.entry(maturity).or_insert(Vec::new()).push((moneyness,volatility));
}
let vol_surface:VolSurface = VolSurface::new(vol_tree, spot_price, spot_date,
DayCountConvention::Act365);
return vol_surface;
}

}

// #[cfg(test)]
// mod tests{
// use super::*;
// use crate::core::quotes::Quote;
// use crate::core::utils::{Contract,ContractStyle};
// use crate::equity::utils::{Engine};
// use crate::core::trade::OptionType;
// use crate::core::trade::OptionStyle;
// use crate::core::trade::OptionStyle::European;
//
// #[test]
// fn test_build_eq_vol(){
// // write a unit test for this function
// let mut contract = C
// let mut contracts:Vec<Box<EquityOption>> = Vec::new();
//
//
// }
File renamed without changes.
File renamed without changes.
File renamed without changes.
68 changes: 68 additions & 0 deletions src/examples/build/build_ir_curve.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{"asset":"IR",
"contracts" : [
{
"action":"PV",
"pricer":"Analytical",
"asset":"IR",
"rate_data":{
"instrument": "Deposit",
"currency": "USD",
"start_date": "0M",
"maturity_date":"1M",
"valuation_date": "0M",
"notional": 1000000,
"fix_rate": 0.055,
"day_count": "A360",
"business_day_adjustment": 0
}
},
{
"action":"PV",
"pricer":"Analytical",
"asset":"IR",
"rate_data":{
"instrument": "Deposit",
"currency": "USD",
"start_date": "0M",
"maturity_date":"3M",
"valuation_date": "0M",
"notional": 1000000,
"fix_rate": 0.05,
"day_count": "A360",
"business_day_adjustment": 0
}
},
{
"action":"PV",
"pricer":"Analytical",
"asset":"IR",
"rate_data":{
"instrument": "FRA",
"currency": "USD",
"start_date": "3M",
"maturity_date":"6M",
"valuation_date": "0M",
"notional": 1000000,
"fix_rate": 0.06,
"day_count": "A360",
"business_day_adjustment": 0
}
},
{
"action":"PV",
"pricer":"Analytical",
"asset":"IR",
"rate_data":{
"instrument": "FRA",
"currency": "USD",
"start_date": "6M",
"maturity_date":"9M",
"valuation_date": "0M",
"notional": 1000000,
"fix_rate": 0.065,
"day_count": "A360",
"business_day_adjustment": 0
}
}
]
}
26 changes: 13 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
// extern crate rand_pcg;

use rand;
use rand::{SeedableRng};
use chrono::{Local,DateTime,NaiveDate,NaiveTime,Datelike, Duration};
use rand::distributions::{Standard,Uniform};
use rand::distributions::Distribution;
use rand_distr::StandardNormal;
//use rand::{SeedableRng};
//use chrono::{Local,DateTime,NaiveDate,NaiveTime,Datelike, Duration};
//use rand::distributions::{Standard,Uniform};
//use rand::distributions::Distribution;
//use rand_distr::StandardNormal;
mod equity;
mod core;
mod utils;
Expand All @@ -25,17 +25,17 @@ use std::io::Read;
use std::{io, thread};
use std::collections::HashMap;
use std::error::Error;
use csv;
//use csv;
//use std::env::{args,Args};
use utils::read_csv;
use utils::RNG;
//use utils::read_csv;
//use utils::RNG;

use std::env::{args, temp_dir};
use rand::Rng;
//use std::env::{args, temp_dir};
//use rand::Rng;
use equity::blackscholes;
use crate::equity::montecarlo;
use clap::{App, Arg, ArgMatches, SubCommand};
use std::env;
//use std::env;
use utils::parse_json;
use std::time::{Instant};

Expand Down Expand Up @@ -146,7 +146,7 @@ fn main() {
let input_dir = dir_matches.value_of("input").unwrap();
let output_dir = dir_matches.value_of("output").unwrap();
let start_time = Instant::now();
let mut output_vec:Vec<String> = Vec::new();
let output_vec:Vec<String> = Vec::new();
let files = fs::read_dir(input_dir).unwrap();
for ifile in files {
let ifile = ifile.unwrap();
Expand All @@ -167,7 +167,7 @@ fn main() {
println!("Time taken to process the dir: {:?}", elapsed_time);
}
("interactive",Some(interactive_matches)) => {
println!("Welcome to Option pricing CLI");

println!("Welcome to Option pricing CLI");
loop {
println!(" Do you want to price option (1) or calculate implied volatility (2)? or (3) to exit");
Expand Down
Loading

0 comments on commit 8787fcb

Please sign in to comment.