CoolFace
Apppublic

Ankit3445/options_pricing

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
AlphaVantageClient.cpp291 linesDownload Raw Back to root
1#include "AlphaVantageClient.hpp"2 3#include <iostream>4#include <sstream>5#include <cmath>6#include <thread>7#include <chrono>8#include <random>9#include <algorithm>10 11#include <boost/beast/core.hpp>12#include <boost/beast/http.hpp>13#include <boost/beast/ssl.hpp>14#include <boost/beast/version.hpp>15#include <boost/asio/connect.hpp>16#include <boost/asio/ip/tcp.hpp>17#include <boost/asio/ssl/error.hpp>18#include <boost/asio/ssl/stream.hpp>19#include <openssl/ssl.h>20#include <nlohmann/json.hpp>21 22namespace beast = boost::beast;23namespace http  = beast::http;24namespace net   = boost::asio;25namespace ssl   = net::ssl;26using tcp       = net::ip::tcp;27 28AlphaVantageClient::AlphaVantageClient(29    const std::vector<std::string>& symbols,30    const std::string& api_key,31    const AppConfig& config,32    std::shared_ptr<ThreadSafeQueue<MarketTick>> queue)33    : symbols_(symbols)34    , api_key_(api_key)35    , config_(config)36    , queue_(std::move(queue))37{38}39 40AlphaVantageClient::~AlphaVantageClient() {41    stop();42}43 44void AlphaVantageClient::start() {45    if (running_.exchange(true)) return;46    thread_ = std::make_unique<std::thread>([this] { polling_loop(); });47}48 49void AlphaVantageClient::stop() {50    running_.store(false);51    if (thread_ && thread_->joinable()) {52        thread_->join();53    }54}55 56void AlphaVantageClient::pause() {57    paused_.store(true);58    std::cout << "[AlphaVantage] Paused" << std::endl;59}60 61void AlphaVantageClient::resume() {62    paused_.store(false);63    std::cout << "[AlphaVantage] Resumed" << std::endl;64}65 66bool AlphaVantageClient::is_paused() const {67    return paused_.load();68}69 70void AlphaVantageClient::request_reset() {71    reset_requested_.store(true);72    paused_.store(false);73    std::cout << "[AlphaVantage] Reset requested" << std::endl;74}75 76void AlphaVantageClient::set_symbols(const std::vector<std::string>& symbols) {77    std::lock_guard<std::mutex> lock(symbols_mutex_);78    symbols_ = symbols;79    symbol_index_.store(0);80    std::cout << "[AlphaVantage] Symbols updated:";81    for (const auto& s : symbols_) std::cout << " " << s;82    std::cout << std::endl;83}84 85std::vector<std::string> AlphaVantageClient::get_symbols() const {86    std::lock_guard<std::mutex> lock(symbols_mutex_);87    return symbols_;88}89 90void AlphaVantageClient::polling_loop() {91    while (running_.load()) {92        if (paused_.load()) {93            std::this_thread::sleep_for(std::chrono::milliseconds(200));94            continue;95        }96 97        if (reset_requested_.exchange(false)) {98            queue_->clear();99            symbol_index_.store(0);100            std::cout << "[AlphaVantage] Queue cleared after reset" << std::endl;101        }102 103        std::string symbol;104        {105            std::lock_guard<std::mutex> lock(symbols_mutex_);106            if (symbols_.empty()) {107                std::this_thread::sleep_for(std::chrono::seconds(1));108                continue;109            }110            symbol = symbols_[symbol_index_.fetch_add(1) % symbols_.size()];111        }112 113        try {114            MarketTick base = fetch_quote(symbol);115            std::vector<MarketTick> chain = expand_option_chain(base);116 117            for (auto& tick : chain) {118                queue_->push(std::move(tick));119            }120 121            std::cout << "[AlphaVantage] " << symbol122                      << " spot=" << base.spotPrice123                      << " -> " << chain.size() << " options queued"124                      << std::endl;125        } catch (const std::exception& ex) {126            std::cerr << "[AlphaVantage] " << symbol << " error: " << ex.what() << std::endl;127        }128 129        for (int i = 0; i < static_cast<int>(config_.rate_limit_sec) && running_.load(); ++i) {130            if (paused_.load() || reset_requested_.load()) break;131            std::this_thread::sleep_for(std::chrono::seconds(1));132        }133    }134}135 136std::vector<MarketTick> AlphaVantageClient::expand_option_chain(const MarketTick& base) {137    std::vector<MarketTick> chain;138    chain.reserve(config_.strike_pct.size() * config_.expiries.size() * ((config_.use_calls ? 1 : 0) + (config_.use_puts ? 1 : 0)));139 140    for (double strike_pct : config_.strike_pct) {141        double strike = std::round(base.spotPrice * strike_pct);142 143        for (double expiry : config_.expiries) {144            if (config_.use_calls) {145                MarketTick tick = base;146                tick.strikePrice   = strike;147                tick.timeToExpiry  = expiry;148                tick.optionType    = OptionType::CALL;149                tick.optionMarketPrice = compute_option_market_price(150                    base.spotPrice, strike, expiry, base.riskFreeRate, OptionType::CALL);151                chain.push_back(std::move(tick));152            }153 154            if (config_.use_puts) {155                MarketTick tick = base;156                tick.strikePrice   = strike;157                tick.timeToExpiry  = expiry;158                tick.optionType    = OptionType::PUT;159                tick.optionMarketPrice = compute_option_market_price(160                    base.spotPrice, strike, expiry, base.riskFreeRate, OptionType::PUT);161                chain.push_back(std::move(tick));162            }163        }164    }165 166    return chain;167}168 169MarketTick AlphaVantageClient::fetch_quote(const std::string& symbol) {170    std::string host = "www.alphavantage.co";171    std::string port = "443";172    std::string target = "/query?function=GLOBAL_QUOTE&symbol=" + symbol + "&apikey=" + api_key_;173 174    net::io_context ioc;175    ssl::context ctx(ssl::context::tls_client);176    ctx.set_default_verify_paths();177    ctx.set_verify_mode(ssl::verify_none);178    ctx.set_options(179        ssl::context::default_workarounds |180        ssl::context::no_sslv2 |181        ssl::context::no_sslv3 |182        ssl::context::single_dh_use183    );184 185    beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx);186    beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(30));187 188    tcp::resolver resolver(ioc);189    auto const results = resolver.resolve(host, port);190    beast::get_lowest_layer(stream).connect(results);191 192    if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {193        throw std::runtime_error("SSL SNI setup failed");194    }195 196    stream.handshake(ssl::stream_base::client);197 198    http::request<http::string_body> req{http::verb::get, target, 11};199    req.set(http::field::host, host);200    req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);201    http::write(stream, req);202 203    beast::flat_buffer buffer;204    http::response<http::dynamic_body> res;205    http::read(stream, buffer, res);206 207    beast::error_code ec;208    stream.shutdown(ec);209 210    auto body = beast::buffers_to_string(res.body().data());211    auto json = nlohmann::json::parse(body);212 213    std::string price_str = "0.0";214    if (json.contains("Global Quote") && json["Global Quote"].contains("05. price")) {215        price_str = json["Global Quote"]["05. price"].get<std::string>();216    } else if (json.contains("Note")) {217        std::cerr << "[AlphaVantage] Rate-limit note: " << json["Note"] << std::endl;218    } else if (json.contains("Information")) {219        std::cerr << "[AlphaVantage] Info: " << json["Information"] << std::endl;220    }221 222    double spot = 0.0;223    try {224        spot = std::stod(price_str);225    } catch (...) {226        spot = 0.0;227    }228    if (spot <= 0.0) {229        spot = synthetic_spot(symbol);230        static thread_local std::mt19937_64 noise_rng(std::random_device{}());231        std::normal_distribution<double> noise(0.0, spot * 0.01);232        spot += noise(noise_rng);233        spot = std::max(spot, 1.0);234        std::cout << "[AlphaVantage] " << symbol << " using synthetic spot $" << spot << std::endl;235    }236 237    auto now = std::chrono::system_clock::now();238    auto tt  = std::chrono::system_clock::to_time_t(now);239    std::stringstream ss;240    ss << std::put_time(std::localtime(&tt), "%Y-%m-%d %H:%M:%S");241    std::string timestamp = ss.str();242 243    MarketTick tick;244    tick.ticker           = symbol;245    tick.timestamp        = timestamp;246    tick.spotPrice        = spot;247    tick.strikePrice      = std::round(spot);248    tick.timeToExpiry     = 0.25;249    tick.riskFreeRate     = 0.04;250    tick.optionType       = OptionType::CALL;251    tick.optionMarketPrice = compute_option_market_price(spot, tick.strikePrice, tick.timeToExpiry, tick.riskFreeRate, OptionType::CALL);252 253    return tick;254}255 256double AlphaVantageClient::synthetic_spot(const std::string& symbol) {257    std::hash<std::string> hasher;258    size_t h = hasher(symbol);259    std::seed_seq seed{static_cast<int>(h & 0xffffffff), static_cast<int>((h >> 32) & 0xffffffff)};260    std::mt19937_64 local_rng(seed);261    std::uniform_real_distribution<double> dist(20.0, 500.0);262    return std::round(dist(local_rng) * 100.0) / 100.0;263}264 265double AlphaVantageClient::compute_option_market_price(266    double spot, double strike, double T, double r, OptionType type) const267{268    double sigma = 0.25;269    double d1 = (std::log(spot / strike) + (r + sigma * sigma * 0.5) * T)270              / (sigma * std::sqrt(T));271    double d2 = d1 - sigma * std::sqrt(T);272    double nd1  = 0.5 * (1.0 + std::erf( d1 / std::sqrt(2.0)));273    double nd2  = 0.5 * (1.0 + std::erf( d2 / std::sqrt(2.0)));274    double n_nd1 = 0.5 * (1.0 + std::erf(-d1 / std::sqrt(2.0)));275    double n_nd2 = 0.5 * (1.0 + std::erf(-d2 / std::sqrt(2.0)));276 277    double price;278    if (type == OptionType::CALL) {279        price = spot * nd1 - strike * std::exp(-r * T) * nd2;280    } else {281        price = strike * std::exp(-r * T) * n_nd2 - spot * n_nd1;282    }283 284    static thread_local std::mt19937_64 rng(std::random_device{}());285    static thread_local std::normal_distribution<double> noise(0.0, 1.0);286    price *= (1.0 + noise(rng) * 0.03);287    price = std::max(price, 0.01);288 289    return price;290}291