/** * @file Pybind.cpp * @brief pybind11 module @c qengine exposing @ref BSWrapper::bs_price_wrapper overloads. */ #include #include #include #include #include #include #include #include "BSWrapper.hpp" namespace py = pybind11; namespace { std::vector to_vector_double(const py::array_t &a) { py::buffer_info info = a.request(); if (info.ndim != 1) { throw std::runtime_error("expected 1-D ndarray for S, K, T, r, sigma"); } const auto *p = static_cast(info.ptr); const ssize_t n = info.shape[0]; return std::vector(p, p + n); } std::vector to_vector_bool_1d(const py::array_t &a) { py::buffer_info info = a.request(); if (info.ndim != 1) { throw std::runtime_error("expected 1-D ndarray for is_call"); } if (info.itemsize != 1) { throw std::runtime_error("is_call: expected a boolean ndarray (dtype=bool)"); } const ssize_t n = info.shape[0]; const auto *p = static_cast(info.ptr); std::vector out(static_cast(n)); for (ssize_t i = 0; i < n; ++i) { out[static_cast(i)] = (p[i] != 0); } return out; } void check_same_length(size_t n, size_t k, const char *name) { if (n != k) { throw std::runtime_error(std::string("length mismatch for ") + name); } } } // namespace PYBIND11_MODULE(qengine, m) { m.doc() = "Binding for the Black Scholes model"; m.def( "bs_price", [](double S, double K, double T, double r, double sigma, bool is_call) { return BSWrapper::bs_price_wrapper(S, K, T, r, sigma, is_call); }, py::arg("S"), py::arg("K"), py::arg("T"), py::arg("r"), py::arg("sigma"), py::arg("is_call")); m.def( "bs_price", [](py::array_t S, py::array_t K, py::array_t T, py::array_t r, py::array_t sigma, py::array_t is_call) { std::vector vS = to_vector_double(S); std::vector vK = to_vector_double(K); std::vector vT = to_vector_double(T); std::vector vr = to_vector_double(r); std::vector vsig = to_vector_double(sigma); std::vector vC = to_vector_bool_1d(is_call); const size_t n = vS.size(); check_same_length(n, vK.size(), "K"); check_same_length(n, vT.size(), "T"); check_same_length(n, vr.size(), "r"); check_same_length(n, vsig.size(), "sigma"); check_same_length(n, vC.size(), "is_call"); return BSWrapper::batch_bs_price_wrapper(vS, vK, vT, vr, vsig, vC); }, py::arg("S"), py::arg("K"), py::arg("T"), py::arg("r"), py::arg("sigma"), py::arg("is_call")); m.def( "bs_price", [](const std::vector &S, const std::vector &K, const std::vector &T, const std::vector &r, const std::vector &sigma, const std::vector &is_call) { return BSWrapper::batch_bs_price_wrapper(S, K, T, r, sigma, is_call); }, py::arg("S"), py::arg("K"), py::arg("T"), py::arg("r"), py::arg("sigma"), py::arg("is_call")); }