Sumitx369/Paper_Trading_Backtesting
2
1#include <pybind11/numpy.h>2#include <pybind11/pybind11.h>3#include <pybind11/stl.h>4 5#include <string>6 7#include "backtest.hpp"8 9namespace py = pybind11;10using Arr = py::array_t<double, py::array::c_style | py::array::forcecast>;11 12static bt::Vec to_vec(Arr arr) {13 auto buf = arr.request();14 const double* p = static_cast<double*>(buf.ptr);15 return bt::Vec(p, p + buf.size);16}17 18static std::vector<bt::Instr> parse_program(const py::list& prog) {19 std::vector<bt::Instr> out;20 out.reserve(py::len(prog));21 for (auto item : prog) {22 auto t = item.cast<py::tuple>(); // (op:int, val:float, a:int, b:int)23 out.push_back({t[0].cast<int>(), t[1].cast<double>(), t[2].cast<int>(),24 t[3].cast<int>()});25 }26 return out;27}28 29PYBIND11_MODULE(trading_engine, m) {30 m.doc() = "C++ backtest engine — indicators + expression VM + portfolio sim";31 32 m.def("ping", []() { return std::string("pong from C++ engine"); },33 "Smoke-test: returns a string from native code.");34 35 m.def(36 "run_backtest",37 [](Arr open, Arr high, Arr low, Arr close, Arr volume, py::list indicators,38 py::list buy_program, py::list sell_program, double starting_capital,39 double fee_bps, double slippage_bps, double stop_loss_pct,40 double take_profit_pct) {41 std::vector<bt::IndicatorSpec> specs;42 specs.reserve(py::len(indicators));43 for (auto item : indicators) {44 auto t = item.cast<py::tuple>(); // (name, p1, p2, p3)45 specs.push_back({t[0].cast<std::string>(), t[1].cast<double>(),46 t[2].cast<double>(), t[3].cast<double>()});47 }48 49 bt::BacktestResult r = bt::run_backtest(50 to_vec(open), to_vec(high), to_vec(low), to_vec(close), to_vec(volume),51 specs, parse_program(buy_program), parse_program(sell_program),52 starting_capital, fee_bps, slippage_bps, stop_loss_pct, take_profit_pct);53 54 py::dict d;55 d["equity"] = py::array_t<double>(r.equity.size(), r.equity.data());56 d["buyhold"] = py::array_t<double>(r.buyhold.size(), r.buyhold.data());57 d["final_value"] = r.final_value;58 d["starting_capital"] = r.starting_capital;59 d["n_bars"] = r.n_bars;60 61 py::list trades;62 for (const auto& tr : r.trades) {63 py::dict td;64 td["entry_index"] = tr.entry_index;65 td["exit_index"] = tr.exit_index;66 td["entry_price"] = tr.entry_price;67 td["exit_price"] = tr.exit_price;68 td["qty"] = tr.qty;69 td["pnl"] = tr.pnl;70 td["return_pct"] = tr.return_pct;71 td["reason"] = tr.reason;72 trades.append(td);73 }74 d["trades"] = trades;75 return d;76 },77 py::arg("open"), py::arg("high"), py::arg("low"), py::arg("close"),78 py::arg("volume"), py::arg("indicators"), py::arg("buy_program"),79 py::arg("sell_program"), py::arg("starting_capital"), py::arg("fee_bps") = 0.0,80 py::arg("slippage_bps") = 0.0, py::arg("stop_loss_pct") = 0.0,81 py::arg("take_profit_pct") = 0.0,82 "Run a long-only backtest. Columns: 0=O 1=H 2=L 3=C 4=V then indicators.");83}84 