rustyqlib/utils/
parse_contracts.rs1use serde::{Deserialize, Serialize};
2use std::fs::File;
3use std::fs;
4use byteorder::{ByteOrder, LittleEndian,BigEndian};
5use std::io::Read;
6use chrono::{Datelike, Local, NaiveDate};
7use crate::core::quotes::Quote;
8use crate::core::termstructure::YieldTermStructure;
9use crate::equity::vanila_option::{EquityOption};
10use crate::equity::utils::{Engine};
13use crate::core::trade;
15use crate::cmdty::cmdty_option;
16use crate::core::traits::{Instrument, Rates};
17use crate::core::utils::{Contract,CombinedContract, ContractOutput, Contracts, OutputJson,EngineType};
18use crate::core::utils::ContractStyle;
19use crate::core::traits::Greeks;
20use std::io::Write;
21use std::env::temp_dir;
22use crate::rates;
24use crate::rates::deposits::Deposit;
25use crate::rates::build_contracts::{build_ir_contracts, build_ir_contracts_from_json, build_term_structure};
26use crate::equity::build_contracts::{build_eq_contracts_from_json};
27use crate::core::vols::VolSurface;
28use crate::equity::handle_equity_contracts::handle_equity_contract;
29
30use rayon::prelude::*;
31use serde_json::Value;
32use crate::core::serialization::{self, Format};
33pub fn save_to_file<'a>(output_folder: &'a str, subfolder: &'a str, filename: &'a str, output: &'a str) -> String {
35 let mut dir = std::path::PathBuf::from(output_folder);
36 if subfolder.len() > 0 {
37 dir.push(subfolder);
38 }
39 let _dir = dir.as_path();
40 if !_dir.exists() {
41 let _ = fs::create_dir(_dir);
42 }
43 dir.push(filename);
44 let mut file = File::create(&dir).expect("Failed to create file");
45 file.write_all(output.as_bytes()).expect("Failed to write to file");
46 return dir.as_path().to_str().unwrap().to_string();
47}
48
49pub fn build_curve(file: &mut File, output_filename: &str) -> () {
51 let mut contents = String::new();
52 file.read_to_string(&mut contents)
53 .expect("Failed to read curve definition file");
54 let format = Format::detect(&contents);
55 let list_contracts: Contracts = serialization::parse(&contents, format)
56 .unwrap_or_else(|e| panic!("Failed to read {format:?} curve definition: {e}"));
57 if list_contracts.contracts.len() == 0 {
58 panic!("No contracts found in JSON file");
59 }
60 else if list_contracts.asset=="EQ"{
61 println!("Building implied volatility surface");
62 let contracts:Vec<Box<EquityOption>> = build_eq_contracts_from_json(list_contracts.contracts);
63 let vol_surface = crate::equity::vol_surface::build_implied_vol_surface(&contracts)
64 .expect("Failed to build implied vol surface");
65 println!("{}", vol_surface);
66 let vol_value = serde_json::to_value(&vol_surface).unwrap();
67 let serialized_vol_surface =
68 serialization::render_value(&vol_value, format, "vol_surface");
69 let filename = format!("vol_surface.{}", format.extension());
70 let out_dir = save_to_file(output_filename, "vol_surface", &filename, &serialized_vol_surface);
71 println!("Volatility surface saved to {}", out_dir);
72 }
73 else if list_contracts.asset=="CO"{
74 panic!("Commodity contracts not supported");
76 }
77 else if list_contracts.asset=="IR"{
78 let mut contracts:Vec<Box<dyn Rates>> = build_ir_contracts_from_json(list_contracts.contracts);
79 let ts = build_term_structure(contracts);
80 let mut output: String = String::new();
81 for i in 0..ts.date.len(){
82 output.push_str(&format!("{},{},{}\n",ts.date[i],ts.discount_factor[i],ts.rate[i]));
83 }
84
85 let out_dir = save_to_file(output_filename, "term_structure", "term_structure.csv", &output);
86 println!("Term structure saved to {}", out_dir);
87
88 }
89 else{
90 panic!("Asset class not supported");
91 }
92}
93
94pub fn parse_contract(file: &mut File, output_filename: &str) {
98 let mut contents = String::new();
99 file.read_to_string(&mut contents)
100 .expect("Failed to read contract file");
101
102 let in_format = Format::detect(&contents);
103 let out_format = Format::from_path(output_filename).unwrap_or(in_format);
104
105 let list_contracts: Contracts = serialization::parse(&contents, in_format)
106 .unwrap_or_else(|e| panic!("Failed to read {in_format:?} contracts: {e}"));
107
108 if list_contracts.contracts.is_empty() {
109 println!("No contracts found in the input document");
110 return;
111 }
112 let mut output_vec: Vec<_> = list_contracts.contracts.par_iter().enumerate()
114 .map(|(index,data)| (index,process_contract(data)))
115 .collect();
116 output_vec.sort_by_key(|k| k.0);
117
118 let results: Vec<Value> = output_vec.into_iter().map(|(_,v)| v).collect();
119 let output_str = serialization::render_results(&results, out_format);
120 let mut file = File::create(output_filename).expect("Failed to create file");
122 file.write_all(output_str.as_bytes()).expect("Failed to write to file");
123}
124pub fn process_contract(data: &Contract) -> serde_json::Value {
125
126 let date = vec![0.01,0.02,0.05,0.1,0.5,1.0,2.0,3.0];
127 let rates = vec![0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05];
128 let ts = YieldTermStructure::new(date,rates);
129
130 if data.action=="PV" && data.asset=="EQ"{
131 return handle_equity_contract(data);
132
133 }
134 else if data.action=="PV" && data.asset=="IR"{
186 let rate_data = data.rate_data.clone().unwrap();
188 let mut start_date_str = rate_data.start_date; let mut maturity_date_str = rate_data.maturity_date;
190 let current_date = Local::now().date_naive();
191 let maturity_date = rates::utils::convert_mm_to_date(maturity_date_str);
192 let start_date = rates::utils::convert_mm_to_date(start_date_str);
193 println!("Maturity Date {:?}",maturity_date);
194 let mut deposit = Deposit {
195 start_date: start_date,
196 maturity_date: maturity_date,
197 valuation_date: current_date,
198 notional: rate_data.notional,
199 fix_rate: rate_data.fix_rate,
200 day_count: rates::utils::DayCountConvention::Act360,
201 business_day_adjustment: 0,
202 term_structure: None
203 };
204 match rate_data.day_count.as_str() {
205 "Act360" |"A360" => {
206 deposit.day_count = rates::utils::DayCountConvention::Act360;
207 }
208 "Act365" |"A365" => {
209 deposit.day_count = rates::utils::DayCountConvention::Act365;
210 }
211 "Thirty360" |"30/360" => {
212 deposit.day_count = rates::utils::DayCountConvention::Thirty360;
213 }
214 _ => {}
215 }
216 let df = deposit.get_discount_factor();
217 println!("Discount Factor {:?}",df);
218 return serde_json::Value::String("Work in progress".to_string());
219 }
220 else{
221 panic!("Invalid action");
222 }
223 return serde_json::Value::String("Invalid Action".to_string());
224
225}