Skip to content

Commit 8787fcb

Browse files
committed
fixed bug in reading date.
1 parent c01a036 commit 8787fcb

14 files changed

+245
-82
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[![Build and Tests](https://github.com/siddharthqs/RustyQLib/actions/workflows/rust.yml/badge.svg)](https://github.com/siddharthqs/RustyQLib/actions/workflows/rust.yml)
2+
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
23

34
# RUSTYQLib :Pricing Options with Confidence using JSON
45
RustyQLib is a lightweight yet robust quantitative finance library designed for pricing options.
@@ -50,6 +51,7 @@ JSON Output Clarity
5051
- [ ] Asian
5152
5253
### Instruments:
54+
#### Equity
5355
- [x] Equity Option
5456
- [ ] Equity Forward Start Option
5557
- [ ] Equity Basket
@@ -58,6 +60,15 @@ JSON Output Clarity
5860
- [ ] Equity Asian
5961
- [ ] Equity Rainbow
6062
- [ ] Equity Chooser
63+
#### Interest Rate
64+
- [x] Deposit
65+
- [x] FRA
66+
- [ ] Interest Rate Swap
67+
#### Commodities
68+
- [x] Commodity Option
69+
- [ ] Commodity Forward Start Option
70+
- [ ] Commodity Barrier
71+
- [ ] Commodity Lookback
6172
6273
6374
### Pricing engines:

src/core/pde/bsm.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/// This is Black Scholes Merton PDE solver using finite difference method
2+
/// $ \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 $
3+
/// $ V(S,T) = max(S-K,0) $
4+
/// $ V(0,t) = 0 $
5+
/// $ V(S,t) \rightarrow S $ as $ S \rightarrow \infty $
6+
///https://de.wikipedia.org/wiki/Thomas-Algorithmus
7+
// pub fn blackscholes_pde(spot:f64,strike:f64,rate:f64,volatility:f64,time_to_maturity:f64,steps:u64,option_type:OptionType) -> f64{
8+
// let mut grid = Grid::new(spot,strike,rate,volatility,time_to_maturity,steps,option_type);
9+
// grid.solve();
10+
// let value = grid.get_value();
11+
// value
12+
// }
13+
// pub struct Grid {
14+
// spot: f64,
15+
// strike: f64,
16+
// rate: f64,
17+
// dividend: f64,
18+
// //volatility:f64,
19+
// time_to_maturity: f64,
20+
// spot_steps: u64,
21+
// time_steps: u64
22+
// }
23+
// impl Grid{
24+
// pub fn payoff(&self,spot:f64) -> f64{
25+
// let payoff = (spot - self.strike).max(0.0);
26+
// payoff
27+
// }
28+
// pub fn build_grid(&self) -> Vec<Vec<f64>>{
29+
// let mut grid:Array2<f64> = Array2::zeros((self.time_steps as usize,self.spot_steps as usize));
30+
// //let mut grid = vec![vec![0.0;self.spot_steps as usize];self.time_steps as usize];
31+
// for i in 0..self.spot_steps as usize{
32+
// grid[0][i] = self.payoff(i as f64);
33+
// }
34+
// grid
35+
// }
36+
// }
37+
38+
39+

src/core/utils.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,15 @@ pub struct ContractOutput {
9393
}
9494

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

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

src/equity/blackscholes.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,14 @@ impl EquityOption {
152152
}
153153
pub fn option_pricing() {
154154
println!("Welcome to the Black-Scholes Option pricer.");
155-
println!("(Step 1/7) What is the current price of the underlying asset?");
155+
println!(" What is the current price of the underlying asset?");
156156
print!(">>");
157157
let mut curr_price = String::new();
158158
io::stdin()
159159
.read_line(&mut curr_price)
160160
.expect("Failed to read line");
161-
println!("(Step 2/7) Do you want a call option ('C') or a put option ('P') ?");
161+
println!(" Do you want a call option ('C') or a put option ('P') ?");
162+
print!(">>");
162163
let mut side_input = String::new();
163164
io::stdin()
164165
.read_line(&mut side_input)
@@ -170,28 +171,36 @@ pub fn option_pricing() {
170171
_ => panic!("Invalide side argument! Side has to be either 'C' or 'P'."),
171172
}
172173
println!("Stike price:");
174+
print!(">>");
173175
let mut strike = String::new();
174176
io::stdin()
175177
.read_line(&mut strike)
176178
.expect("Failed to read line");
177179
println!("Expected annualized volatility in %:");
178180
println!("E.g.: Enter 50% chance as 0.50 ");
181+
print!(">>");
179182
let mut vol = String::new();
180183
io::stdin()
181184
.read_line(&mut vol)
182185
.expect("Failed to read line");
183186

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

189193
let mut expiry = String::new();
194+
println!("E.g.: Enter 2020-12-31 for 31st December 2020");
195+
print!(">>");
190196
io::stdin()
191197
.read_line(&mut expiry)
192198
.expect("Failed to read line");
193-
let future_date = NaiveDate::parse_from_str(&expiry, "%Y-%m-%d").expect("Invalid date format");
199+
println!("{:?}", expiry.trim());
200+
let _d = expiry.trim();
201+
let future_date = NaiveDate::parse_from_str(&_d, "%Y-%m-%d").expect("Invalid date format");
194202
println!("Dividend yield on this stock:");
203+
print!(">>");
195204
let mut div = String::new();
196205
io::stdin()
197206
.read_line(&mut div)

src/equity/build_contracts.rs

+2-18
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,7 @@ use crate::core::utils::{Contract,ContractStyle};
1414
use crate::equity::utils::{Engine};
1515
use std::collections::BTreeMap;
1616

17-
pub fn build_eq_contracts_from_json(data: Vec<Contract>) -> Vec<Box<EquityOption>> {
18-
let derivatives:Vec<Box<EquityOption>> = data.iter().map(|x| EquityOption::from_json(x.clone())).collect();
17+
pub fn build_eq_contracts_from_json(mut data: Vec<Contract>) -> Vec<Box<EquityOption>> {
18+
let derivatives:Vec<Box<EquityOption>> = data.iter().map(|x| EquityOption::from_json(&x)).collect();
1919
return derivatives;
2020
}
21-
pub fn build_volatility_surface(mut contracts:Vec<Box<EquityOption>>) -> VolSurface {
22-
23-
let mut vol_tree:BTreeMap<NaiveDate,Vec<(f64,f64)>> = BTreeMap::new();
24-
let spot_date = contracts[0].valuation_date;
25-
let spot_price = contracts[0].underlying_price.value;
26-
for i in 0..contracts.len(){
27-
let mut contract = contracts[i].as_mut();
28-
let moneyness = contract.underlying_price.value / contract.strike_price as f64;
29-
let volatility = contract.get_imp_vol();
30-
let maturity = contract.maturity_date;
31-
vol_tree.entry(maturity).or_insert(Vec::new()).push((moneyness,volatility));
32-
}
33-
let vol_surface:VolSurface = VolSurface::new(vol_tree, spot_price, spot_date,
34-
DayCountConvention::Act365);
35-
return vol_surface;
36-
}

src/equity/vanila_option.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl Instrument for EquityOption {
3333
}
3434
}
3535
}
36-
/// Equity Option represents a real world equity option contract
36+
/// This struct represents a real world equity option contract
3737
#[derive(Debug)]
3838
pub struct EquityOption {
3939
pub option_type: OptionType,
@@ -59,8 +59,8 @@ impl EquityOption{
5959
}
6060
}
6161
impl EquityOption {
62-
pub fn from_json(data: Contract) -> Box<EquityOption> {
63-
let market_data = data.market_data.unwrap();
62+
pub fn from_json(data: &Contract) -> Box<EquityOption> {
63+
let market_data = data.market_data.as_ref().unwrap();
6464
let underlying_quote = Quote::new(market_data.underlying_price);
6565
//TODO: Add term structure
6666
let date = vec![0.01, 0.02, 0.05, 0.1, 0.5, 1.0, 2.0, 3.0];
@@ -168,7 +168,7 @@ mod tests {
168168
style: Some("European".to_string()),
169169
rate_data: None
170170
};
171-
let option = EquityOption::from_json(data);
171+
let option = EquityOption::from_json(&data);
172172
assert_eq!(option.option_type, OptionType::Call);
173173
assert_eq!(option.transection, Transection::Buy);
174174
assert_eq!(option.underlying_price.value, 100.0);

src/equity/vol_surface.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize};
22
use std::collections::{BTreeMap, HashMap};
33
use crate::rates::utils::{DayCountConvention};
44
use chrono::{NaiveDate};
5+
use crate::core::trade::OptionType;
6+
use super::vanila_option::{EquityOption};
57

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

32-
}
44+
},
45+
OptionType::Put => {
46+
moneyness = contract.strike_price / contract.underlying_price.value as f64;
47+
}
48+
_ => {
49+
panic!("Option type not supported");
50+
}
51+
}
52+
let volatility = contract.get_imp_vol();
53+
let maturity = contract.maturity_date;
54+
vol_tree.entry(maturity).or_insert(Vec::new()).push((moneyness,volatility));
55+
}
56+
let vol_surface:VolSurface = VolSurface::new(vol_tree, spot_price, spot_date,
57+
DayCountConvention::Act365);
58+
return vol_surface;
59+
}
60+
61+
}
62+
63+
// #[cfg(test)]
64+
// mod tests{
65+
// use super::*;
66+
// use crate::core::quotes::Quote;
67+
// use crate::core::utils::{Contract,ContractStyle};
68+
// use crate::equity::utils::{Engine};
69+
// use crate::core::trade::OptionType;
70+
// use crate::core::trade::OptionStyle;
71+
// use crate::core::trade::OptionStyle::European;
72+
//
73+
// #[test]
74+
// fn test_build_eq_vol(){
75+
// // write a unit test for this function
76+
// let mut contract = C
77+
// let mut contracts:Vec<Box<EquityOption>> = Vec::new();
78+
//
79+
//
80+
// }
File renamed without changes.
File renamed without changes.
File renamed without changes.
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{"asset":"IR",
2+
"contracts" : [
3+
{
4+
"action":"PV",
5+
"pricer":"Analytical",
6+
"asset":"IR",
7+
"rate_data":{
8+
"instrument": "Deposit",
9+
"currency": "USD",
10+
"start_date": "0M",
11+
"maturity_date":"1M",
12+
"valuation_date": "0M",
13+
"notional": 1000000,
14+
"fix_rate": 0.055,
15+
"day_count": "A360",
16+
"business_day_adjustment": 0
17+
}
18+
},
19+
{
20+
"action":"PV",
21+
"pricer":"Analytical",
22+
"asset":"IR",
23+
"rate_data":{
24+
"instrument": "Deposit",
25+
"currency": "USD",
26+
"start_date": "0M",
27+
"maturity_date":"3M",
28+
"valuation_date": "0M",
29+
"notional": 1000000,
30+
"fix_rate": 0.05,
31+
"day_count": "A360",
32+
"business_day_adjustment": 0
33+
}
34+
},
35+
{
36+
"action":"PV",
37+
"pricer":"Analytical",
38+
"asset":"IR",
39+
"rate_data":{
40+
"instrument": "FRA",
41+
"currency": "USD",
42+
"start_date": "3M",
43+
"maturity_date":"6M",
44+
"valuation_date": "0M",
45+
"notional": 1000000,
46+
"fix_rate": 0.06,
47+
"day_count": "A360",
48+
"business_day_adjustment": 0
49+
}
50+
},
51+
{
52+
"action":"PV",
53+
"pricer":"Analytical",
54+
"asset":"IR",
55+
"rate_data":{
56+
"instrument": "FRA",
57+
"currency": "USD",
58+
"start_date": "6M",
59+
"maturity_date":"9M",
60+
"valuation_date": "0M",
61+
"notional": 1000000,
62+
"fix_rate": 0.065,
63+
"day_count": "A360",
64+
"business_day_adjustment": 0
65+
}
66+
}
67+
]
68+
}

src/main.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
// extern crate rand_pcg;
44

55
use rand;
6-
use rand::{SeedableRng};
7-
use chrono::{Local,DateTime,NaiveDate,NaiveTime,Datelike, Duration};
8-
use rand::distributions::{Standard,Uniform};
9-
use rand::distributions::Distribution;
10-
use rand_distr::StandardNormal;
6+
//use rand::{SeedableRng};
7+
//use chrono::{Local,DateTime,NaiveDate,NaiveTime,Datelike, Duration};
8+
//use rand::distributions::{Standard,Uniform};
9+
//use rand::distributions::Distribution;
10+
//use rand_distr::StandardNormal;
1111
mod equity;
1212
mod core;
1313
mod utils;
@@ -25,17 +25,17 @@ use std::io::Read;
2525
use std::{io, thread};
2626
use std::collections::HashMap;
2727
use std::error::Error;
28-
use csv;
28+
//use csv;
2929
//use std::env::{args,Args};
30-
use utils::read_csv;
31-
use utils::RNG;
30+
//use utils::read_csv;
31+
//use utils::RNG;
3232

33-
use std::env::{args, temp_dir};
34-
use rand::Rng;
33+
//use std::env::{args, temp_dir};
34+
//use rand::Rng;
3535
use equity::blackscholes;
3636
use crate::equity::montecarlo;
3737
use clap::{App, Arg, ArgMatches, SubCommand};
38-
use std::env;
38+
//use std::env;
3939
use utils::parse_json;
4040
use std::time::{Instant};
4141

@@ -146,7 +146,7 @@ fn main() {
146146
let input_dir = dir_matches.value_of("input").unwrap();
147147
let output_dir = dir_matches.value_of("output").unwrap();
148148
let start_time = Instant::now();
149-
let mut output_vec:Vec<String> = Vec::new();
149+
let output_vec:Vec<String> = Vec::new();
150150
let files = fs::read_dir(input_dir).unwrap();
151151
for ifile in files {
152152
let ifile = ifile.unwrap();
@@ -167,7 +167,7 @@ fn main() {
167167
println!("Time taken to process the dir: {:?}", elapsed_time);
168168
}
169169
("interactive",Some(interactive_matches)) => {
170-
println!("Welcome to Option pricing CLI");
170+
171171
println!("Welcome to Option pricing CLI");
172172
loop {
173173
println!(" Do you want to price option (1) or calculate implied volatility (2)? or (3) to exit");

0 commit comments

Comments
 (0)