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:
@@ -79,6 +79,10 @@ public sealed class ReplayEngine(
|
||||
var daySignals = await GenerateSignalsAsync(modelId, session, ohlcvBars, cancellationToken);
|
||||
signals.AddRange(daySignals);
|
||||
|
||||
// Calculate current portfolio heat (% of capital at risk in open positions)
|
||||
var currentExposure = currentPortfolio.Positions
|
||||
.Sum(pos => pos.Value * GetClosePrice(session, pos.Key, ohlcvBars)) / currentPortfolio.TotalValue;
|
||||
|
||||
// Convert signals to orders with dynamic position sizing
|
||||
var dayOrders = daySignals
|
||||
.Select(s =>
|
||||
@@ -86,11 +90,21 @@ public sealed class ReplayEngine(
|
||||
var closePrice = GetClosePrice(session, s.Ticker, ohlcvBars);
|
||||
if (closePrice <= 0) return null;
|
||||
|
||||
// Position size: 2% of portfolio per signal (Kelly Criterion simplified)
|
||||
// Higher confidence → larger position (0.5x to 1.5x multiplier)
|
||||
var riskPercentage = 0.02m * s.Confidence * 2m; // Ranges 0.01-0.03
|
||||
// Dynamic position sizing: Kelly Criterion + heat/confidence adjustment
|
||||
// Base: 2% of portfolio per signal
|
||||
// Multipliers: (1) Confidence: 0.5x-1.5x, (2) Heat: reduce if over 60% exposed
|
||||
var baseRisk = 0.02m;
|
||||
var confidenceMultiplier = 0.5m + (s.Confidence * 1.0m); // 0.5x-1.5x
|
||||
var heatMultiplier = currentExposure > 0.60m ? 0.5m : 1.0m; // Reduce if hot
|
||||
|
||||
var riskPercentage = baseRisk * confidenceMultiplier * heatMultiplier;
|
||||
var targetCash = currentPortfolio.TotalValue * riskPercentage;
|
||||
var quantity = Math.Max(1L, (long)(targetCash / closePrice));
|
||||
|
||||
// Single-ticker cap: max 15% of portfolio per position
|
||||
var maxTickerExposure = currentPortfolio.TotalValue * 0.15m;
|
||||
var maxQuantity = Math.Max(1L, (long)(maxTickerExposure / closePrice));
|
||||
|
||||
var quantity = Math.Min(maxQuantity, Math.Max(1L, (long)(targetCash / closePrice)));
|
||||
|
||||
return new Order(
|
||||
OrderId: Guid.NewGuid(),
|
||||
|
||||
Reference in New Issue
Block a user