39 std::vector<Position> positions;
42 double take_profit_pct;
43 double last_price = std::nan(
"");
46 void liquidate_position_at(
size_t i,
double price, int64_t timestamp,
47 bool is_stop_loss =
false,
bool is_take_profit =
false) {
49 double proceeds = pos.
quantity * price;
50 double commission = proceeds * tx_cost_pct;
51 stats.add_costs(commission);
52 cash += proceeds - commission;
54 double profit = (price - pos.
price) * pos.
quantity - commission;
55 stats.record_trade_close(timestamp, pos.
quantity, pos.
price, price, profit,
56 is_stop_loss, is_take_profit);
58 positions[i] = positions.back();
62 void liquidate_all_at_price(
double price, int64_t timestamp) {
63 for (
const auto& p : positions) {
64 double proceeds = p.quantity * price;
65 double commission = proceeds * tx_cost_pct;
66 stats.add_costs(commission);
67 cash += proceeds - commission;
69 double profit = (price - p.price) * p.quantity - commission;
70 stats.record_trade_close(timestamp, p.quantity, p.price, price, profit,
false,
false);
75 double compute_holdings_value()
const {
76 double holdings = 0.0;
77 for (
const auto& p : positions) {
78 holdings += p.quantity * last_price;
83 double compute_total_quantity()
const {
85 for (
const auto& p : positions) {
91 double compute_total_value()
const {
92 return cash + compute_holdings_value();
95 void check_stop_loss_take_profit(
double current_price, int64_t timestamp) {
96 for (
size_t i = 0; i < positions.size();) {
97 bool should_liquidate =
false;
98 bool is_stop_loss =
false;
99 bool is_take_profit =
false;
102 if (!std::isnan(stop_loss_pct)) {
103 double stop_price = p.
price * (1.0 - stop_loss_pct);
104 if (current_price <= stop_price) {
105 should_liquidate =
true;
110 if (!should_liquidate && !std::isnan(take_profit_pct)) {
111 double tp_price = p.
price * (1.0 + take_profit_pct);
112 if (current_price >= tp_price) {
113 should_liquidate =
true;
114 is_take_profit =
true;
118 if (should_liquidate) {
119 stats.increment_trades();
120 liquidate_position_at(i, current_price, timestamp, is_stop_loss, is_take_profit);
127 void process_signal(
const Signal& signal) {
131 execute_sell(signal);
135 void execute_buy(
const Signal& signal) {
136 double unit_cost = signal.
price * (1.0 + tx_cost_pct);
137 double qty = std::floor(cash / unit_cost);
139 double cost = qty * signal.
price;
140 double commission = cost * tx_cost_pct;
141 stats.add_costs(commission);
142 cash -= cost + commission;
143 stats.increment_trades();
149 void execute_sell(
const Signal& signal) {
150 size_t num_positions = positions.size();
151 if (num_positions > 0) {
152 stats.increment_trades();
157 double get_holdings_value()
const {
158 return compute_holdings_value();
161 double get_total_quantity()
const {
162 return compute_total_quantity();
167 double txCostPct = 0.0,
168 double stopLossPct = std::nan(
""),
169 double takeProfitPct = std::nan(
""))
170 : init_cash(initCash), cash(initCash),
171 tx_cost_pct(txCostPct), stop_loss_pct(stopLossPct),
172 take_profit_pct(takeProfitPct) {}
175 if (signal.
price <= 0.0)
return;
176 last_price = signal.
price;
178 if (stats.is_initialized()) {
183 process_signal(signal);
185 stats.record_equity(signal.
timestamp, compute_total_value(), signal.
price);
188 friend std::ostream&
operator<<(std::ostream& os,
BasicPortfolio(double initCash=100000.0, double txCostPct=0.0, double stopLossPct=std::nan(""), double takeProfitPct=std::nan(""))
Definition portfolios.h:166