Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion include/pineforge/engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,19 @@ class BacktestEngine {
return floored < qty ? floored : qty;
}

// TradingView reserves the entry commission when sizing percent_of_equity:
// it sizes the notional so that notional + entry_fee <= equity*pct, i.e.
// divides the sizing cash by (1 + commRate). Proven from TV exports for
// BOTH fractional (pct=10) and all-in (pct=100) sizing — the reservation is
// not gated on headroom (KI-52 probes: ki52-pct-equity-commission-{frac,allin},
// first-entry qty = equity/(price*(1+commRate)) to the lot step, 16/16). Only
// percent commission reserves; cash-per-order/contract and a zero rate are
// exact no-ops, so FIXED/CASH qty types and commission_value_==0 are unchanged.
double reserve_percent_commission(double cash) const {
return (commission_type_ == CommissionType::PERCENT && commission_value_ > 0.0)
? cash / (1.0 + commission_value_ / 100.0) : cash;
}

double calc_qty(double fill_price) const {
switch (default_qty_type_) {
case QtyType::FIXED:
Expand All @@ -849,7 +862,7 @@ class BacktestEngine {
// percent orders from the live equity snapshot so pyramid adds
// and same-bar/re-entry sizing see unrealized PnL.
double equity = current_equity() + open_profit(current_bar_.close);
double cash = equity * (default_qty_value_ / 100.0) / account_currency_fx_;
double cash = reserve_percent_commission(equity * (default_qty_value_ / 100.0)) / account_currency_fx_;
// Reject (qty 0) on a non-finite / non-positive fill price — a
// degenerate $0/NaN print must NOT size as the raw % number.
return (std::isfinite(fill_price) && fill_price > 0)
Expand Down
2 changes: 1 addition & 1 deletion src/engine_orders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ double BacktestEngine::calc_qty_for_type(double fill_price, double qty_value, in
}
if (qty_type == static_cast<int>(QtyType::PERCENT_OF_EQUITY)) {
double equity = current_equity() + open_profit(current_bar_.close);
double cash = equity * (qty_value / 100.0);
double cash = reserve_percent_commission(equity * (qty_value / 100.0));
// Reject (qty 0) on a non-finite / non-positive fill price — a degenerate
// $0/NaN print must NOT size as the raw % number (silent wrong-qty bug).
// One contract's currency exposure is fill_price × pointvalue (1.0 for
Expand Down
Loading