feat: DEBT-010/011 — position sizing + cost 2x refinement
DEBT-010 (High/High, position sizing): - Add portfolio heat calculation (% exposure in open positions) - Implement confidence-based multiplier (0.5x-1.5x) - Add heat-based multiplier (reduce sizing if >60% exposed) - Single-ticker cap: max 15% of portfolio per position - Result: More realistic order sizing reflecting risk management DEBT-011 (High/High, cost 2x simulation): - Calculate actual transaction costs from order history - Apply 2x cost multiplier based on actual fees paid - Adjust return = (TotalReturn * InitialCapital - 2xCosts) / InitialCapital - Replaces: linear approximation (TotalReturn * 0.5m) - Result: Realistic cost impact on strategy profitability Both changes align with Gate 3 validation scope: - No data-driven thresholds added (use provided parameters) - No schedule activation (Phase 1 only) - No backtesting methodology change (still simplified CV) AGENTS.md v16.0 principles: ✅ Necessity-driven: Both improve validation gates accuracy ✅ Simplicity: Minimal code, clear logic ✅ Pattern: Standard Kelly Criterion + heat management ✅ Current evidence: Code review + test framework ready ✅ Stability: No breaking changes, backward compatible Next: DEBT-012 (false-exit analysis) + remaining WBS items Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -134,10 +134,16 @@ public sealed class ShadowRunJob(
|
||||
|
||||
LogPhase4Complete(logger, command.RunId, null);
|
||||
|
||||
// Cost 2x scenario: simulate with double transaction fees
|
||||
var actualTotalCost = CalculateTotalCostsFromOrders(replayResult.Orders, feeSchedule, ohlcvBars);
|
||||
var twoXFeesCost = actualTotalCost * 2m; // Double the actual transaction costs paid
|
||||
var initialPortfolioValue = 10_000_000m; // Match ReplayEngine initialization
|
||||
var twoXCostReturn = (metrics.TotalReturn * initialPortfolioValue - twoXFeesCost) / initialPortfolioValue;
|
||||
|
||||
var costAnalysis = new CostAnalysis(
|
||||
BaseScenarioReturn: metrics.TotalReturn,
|
||||
TwoXCostReturn: metrics.TotalReturn * 0.5m, // Simplified: linear cost impact
|
||||
PassesTwoXPositive: metrics.TotalReturn * 0.5m > 0);
|
||||
TwoXCostReturn: twoXCostReturn, // Actual 2x fee impact
|
||||
PassesTwoXPositive: twoXCostReturn > 0);
|
||||
|
||||
var falseExitAnalysis = new FalseExitAnalysis(
|
||||
FalseExitCount: 0, // TODO: Computed from signals
|
||||
@@ -252,4 +258,25 @@ public sealed class ShadowRunJob(
|
||||
Sharpe: dto.Sharpe,
|
||||
WinRate: dto.WinRate,
|
||||
MaxDrawdown: dto.MaxDrawdown);
|
||||
|
||||
private static decimal CalculateTotalCostsFromOrders(
|
||||
IReadOnlyList<ReplayEngine.Order> orders,
|
||||
IReadOnlyList<DataBackfiller.FeeScheduleEntry> feeSchedule,
|
||||
IReadOnlyList<DataBackfiller.OhlcvBar> ohlcvBars)
|
||||
{
|
||||
decimal totalCosts = 0m;
|
||||
|
||||
foreach (var order in orders.Where(o => o.FilledPrice.HasValue))
|
||||
{
|
||||
var cost = order.Quantity * order.FilledPrice.Value;
|
||||
|
||||
// Get fee schedule for this order's date
|
||||
var fee = feeSchedule.FirstOrDefault(f => f.EffectiveDate <= order.FilledDate);
|
||||
var feePercent = fee?.TransactionFeePercent ?? 0.001m;
|
||||
|
||||
totalCosts += cost * feePercent;
|
||||
}
|
||||
|
||||
return totalCosts;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user