Ankit3445/options_pricing
0
1#include "Strategy.hpp"2#include <cmath>3#include <sstream>4#include <algorithm>5#include <numeric>6 7double StrategyBuilder::norm_cdf(double x) {8 return 0.5 * (1.0 + std::erf(x / std::sqrt(2.0)));9}10 11double StrategyBuilder::bs_price(double S, double K, double T, double r, double sigma, OptionType type) {12 double d1 = (std::log(S / K) + (r + sigma * sigma * 0.5) * T) / (sigma * std::sqrt(T));13 double d2 = d1 - sigma * std::sqrt(T);14 if (type == OptionType::CALL)15 return S * norm_cdf(d1) - K * std::exp(-r * T) * norm_cdf(d2);16 else17 return K * std::exp(-r * T) * norm_cdf(-d2) - S * norm_cdf(-d1);18}19 20Greeks StrategyBuilder::bs_greeks(double S, double K, double T, double r, double sigma, OptionType type) {21 Greeks g;22 if (T <= 0.0 || sigma <= 0.0) { g.valid = false; return g; }23 double d1 = (std::log(S / K) + (r + sigma * sigma * 0.5) * T) / (sigma * std::sqrt(T));24 double d2 = d1 - sigma * std::sqrt(T);25 double pdf = std::exp(-0.5 * d1 * d1) / std::sqrt(2.0 * M_PI);26 if (type == OptionType::CALL) {27 g.price = S * norm_cdf(d1) - K * std::exp(-r * T) * norm_cdf(d2);28 g.delta = norm_cdf(d1);29 g.gamma = pdf / (S * sigma * std::sqrt(T));30 g.vega = S * pdf * std::sqrt(T) / 100.0;31 g.theta = (-S * pdf * sigma / (2.0 * std::sqrt(T)) - r * K * std::exp(-r * T) * norm_cdf(d2)) / 365.0;32 g.rho = K * T * std::exp(-r * T) * norm_cdf(d2) / 100.0;33 } else {34 g.price = K * std::exp(-r * T) * norm_cdf(-d2) - S * norm_cdf(-d1);35 g.delta = norm_cdf(d1) - 1.0;36 g.gamma = pdf / (S * sigma * std::sqrt(T));37 g.vega = S * pdf * std::sqrt(T) / 100.0;38 g.theta = (-S * pdf * sigma / (2.0 * std::sqrt(T)) + r * K * std::exp(-r * T) * norm_cdf(-d2)) / 365.0;39 g.rho = -K * T * std::exp(-r * T) * norm_cdf(-d2) / 100.0;40 }41 g.impliedVol = sigma;42 g.valid = true;43 return g;44}45 46// ── Strategy Factories ──47StrategyDef StrategyBuilder::covered_call(const std::string& ticker, double spot, double strike, double expiry) {48 double sigma = 0.25;49 StrategyDef s;50 s.name = "Covered Call"; s.ticker = ticker; s.spot = spot; s.rate = 0.04;51 s.legs = {{strike, expiry, OptionType::CALL, -1, bs_price(spot, strike, expiry, 0.04, sigma, OptionType::CALL)}};52 return s;53}54 55StrategyDef StrategyBuilder::protective_put(const std::string& ticker, double spot, double strike, double expiry) {56 double sigma = 0.25;57 StrategyDef s;58 s.name = "Protective Put"; s.ticker = ticker; s.spot = spot; s.rate = 0.04;59 s.legs = {{strike, expiry, OptionType::PUT, 1, bs_price(spot, strike, expiry, 0.04, sigma, OptionType::PUT)}};60 return s;61}62 63StrategyDef StrategyBuilder::straddle(const std::string& ticker, double spot, double strike, double expiry) {64 double sigma = 0.25;65 StrategyDef s;66 s.name = "Straddle"; s.ticker = ticker; s.spot = spot; s.rate = 0.04;67 s.legs = {68 {strike, expiry, OptionType::CALL, 1, bs_price(spot, strike, expiry, 0.04, sigma, OptionType::CALL)},69 {strike, expiry, OptionType::PUT, 1, bs_price(spot, strike, expiry, 0.04, sigma, OptionType::PUT)}70 };71 return s;72}73 74StrategyDef StrategyBuilder::strangle(const std::string& ticker, double spot, double low_strike, double high_strike, double expiry) {75 double sigma = 0.25;76 StrategyDef s;77 s.name = "Strangle"; s.ticker = ticker; s.spot = spot; s.rate = 0.04;78 s.legs = {79 {low_strike, expiry, OptionType::PUT, 1, bs_price(spot, low_strike, expiry, 0.04, sigma, OptionType::PUT)},80 {high_strike, expiry, OptionType::CALL, 1, bs_price(spot, high_strike, expiry, 0.04, sigma, OptionType::CALL)}81 };82 return s;83}84 85StrategyDef StrategyBuilder::bull_call_spread(const std::string& ticker, double spot, double low_strike, double high_strike, double expiry) {86 double sigma = 0.25;87 StrategyDef s;88 s.name = "Bull Call Spread"; s.ticker = ticker; s.spot = spot; s.rate = 0.04;89 s.legs = {90 {low_strike, expiry, OptionType::CALL, 1, bs_price(spot, low_strike, expiry, 0.04, sigma, OptionType::CALL)},91 {high_strike, expiry, OptionType::CALL, -1, bs_price(spot, high_strike, expiry, 0.04, sigma, OptionType::CALL)}92 };93 return s;94}95 96StrategyDef StrategyBuilder::bear_put_spread(const std::string& ticker, double spot, double low_strike, double high_strike, double expiry) {97 double sigma = 0.25;98 StrategyDef s;99 s.name = "Bear Put Spread"; s.ticker = ticker; s.spot = spot; s.rate = 0.04;100 s.legs = {101 {high_strike, expiry, OptionType::PUT, 1, bs_price(spot, high_strike, expiry, 0.04, sigma, OptionType::PUT)},102 {low_strike, expiry, OptionType::PUT, -1, bs_price(spot, low_strike, expiry, 0.04, sigma, OptionType::PUT)}103 };104 return s;105}106 107StrategyDef StrategyBuilder::butterfly(const std::string& ticker, double spot, double low, double mid, double high, double expiry) {108 double sigma = 0.25;109 double r = 0.04;110 StrategyDef s;111 s.name = "Butterfly"; s.ticker = ticker; s.spot = spot; s.rate = r;112 s.legs = {113 {low, expiry, OptionType::CALL, 1, bs_price(spot, low, expiry, r, sigma, OptionType::CALL)},114 {mid, expiry, OptionType::CALL, -2, bs_price(spot, mid, expiry, r, sigma, OptionType::CALL)},115 {high, expiry, OptionType::CALL, 1, bs_price(spot, high, expiry, r, sigma, OptionType::CALL)}116 };117 return s;118}119 120StrategyDef StrategyBuilder::iron_condor(const std::string& ticker, double spot, double put_low, double put_high, double call_low, double call_high, double expiry) {121 double sigma = 0.25;122 double r = 0.04;123 StrategyDef s;124 s.name = "Iron Condor"; s.ticker = ticker; s.spot = spot; s.rate = r;125 s.legs = {126 {put_low, expiry, OptionType::PUT, -1, bs_price(spot, put_low, expiry, r, sigma, OptionType::PUT)},127 {put_high, expiry, OptionType::PUT, 1, bs_price(spot, put_high, expiry, r, sigma, OptionType::PUT)},128 {call_low, expiry, OptionType::CALL, 1, bs_price(spot, call_low, expiry, r, sigma, OptionType::CALL)},129 {call_high,expiry, OptionType::CALL, -1, bs_price(spot, call_high, expiry, r, sigma, OptionType::CALL)}130 };131 return s;132}133 134Greeks StrategyBuilder::greeks_at_spot(const StrategyDef& strat, double spot) {135 Greeks combined;136 double sigma = 0.25;137 for (const auto& leg : strat.legs) {138 Greeks g = bs_greeks(spot, leg.strike, leg.expiry, strat.rate, sigma, leg.type);139 combined.price += g.price * leg.quantity;140 combined.delta += g.delta * leg.quantity;141 combined.gamma += g.gamma * leg.quantity;142 combined.vega += g.vega * leg.quantity;143 combined.theta += g.theta * leg.quantity;144 combined.rho += g.rho * leg.quantity;145 }146 combined.valid = true;147 return combined;148}149 150nlohmann::json StrategyBuilder::pnl_at_expiry(const StrategyDef& strat, double spot_min, double spot_max, int steps) {151 double total_cost = 0.0;152 for (const auto& leg : strat.legs)153 total_cost += leg.entry_price * leg.quantity;154 155 nlohmann::json data = nlohmann::json::array();156 double step = (spot_max - spot_min) / steps;157 for (int i = 0; i <= steps; ++i) {158 double S = spot_min + i * step;159 // At expiry, option value = intrinsic value160 double pnl = -total_cost;161 for (const auto& leg : strat.legs) {162 double intrinsic = 0.0;163 if (leg.type == OptionType::CALL)164 intrinsic = std::max(S - leg.strike, 0.0);165 else166 intrinsic = std::max(leg.strike - S, 0.0);167 pnl += intrinsic * leg.quantity;168 }169 Greeks g = greeks_at_spot(strat, S);170 data.push_back({{"spot", S}, {"pnl", pnl}, {"delta", g.delta}, {"gamma", g.gamma}});171 }172 return data;173}174 175nlohmann::json StrategyBuilder::to_json(const StrategyDef& strat) {176 nlohmann::json legs = nlohmann::json::array();177 double total_cost = 0.0;178 for (const auto& leg : strat.legs) {179 total_cost += leg.entry_price * leg.quantity;180 legs.push_back({181 {"strike", leg.strike}, {"expiry", leg.expiry},182 {"type", leg.type == OptionType::CALL ? "CALL" : "PUT"},183 {"qty", leg.quantity}, {"entry_price", leg.entry_price}184 });185 }186 Greeks g = greeks_at_spot(strat, strat.spot);187 return {188 {"name", strat.name}, {"ticker", strat.ticker}, {"spot", strat.spot},189 {"legs", legs}, {"total_cost", total_cost},190 {"price", g.price}, {"delta", g.delta}, {"gamma", g.gamma},191 {"vega", g.vega}, {"theta", g.theta}, {"rho", g.rho},192 {"pnl_data", pnl_at_expiry(strat, strat.spot * 0.5, strat.spot * 1.5, 50)}193 };194}195 