Fix stop/target ordering, P&L wiring, dynamic targets, confluence wiring
Some checks failed
Build and Test / build (push) Has been cancelled
Some checks failed
Build and Test / build (push) Has been cancelled
- Move SetStopLoss/SetProfitTarget before EnterLong/EnterShort in SubmitOrderToNT8(). NT8 requires stop/target pre-registered to the signal name before entry fires — calling after caused silent fallback to strategy defaults in backtest, nullifying all dynamic target scaling. Add [dynamic] tag to SUBMIT log line for observability. - Wire OnPositionUpdate() in NT8StrategyBase to call _riskManager.OnPnLUpdate() and PortfolioRiskManager.ReportPnL() on every position change. Daily loss limit checks were evaluating against PnL permanently — safety net now live. - Fix BasicRiskManager.CheckEmergencyConditions() hardcoded 1000 limit. Add dailyLossLimit constructor overload; emergency halt now fires at 90% of the configured DailyLossLimit, not a hardcoded . - Add AVWAP slope hard veto in SimpleORBStrategy.OnBar(). Trend=0.00 (AVWAP working against trade direction) can no longer pass grade filter. Pre-scoring veto prevents high gap/volume scores from masking a directionally broken setup. - Raise default MinTradeGrade from 4 (B) to 5 (A) in both SimpleORBStrategy and SimpleORBNT8 defaults. - Scale TargetTicks dynamically in CreateIntent() based on ORB/ATR ratio (0.75x-1.75x of base target). Tight ORBs get extended targets; wide ORBs get tightened. Hard floor at stopTicks+4. - Add NarrowRange, OrbRangeVsAtr, GapDirectionAlignment, BreakoutVolumeStrength, PriorDayCloseStrength default weights in ConfluenceScorer constructor. All 10 factors now registered. - Fix session_open_price tracking for GapDirectionAlignment factor. TodayOpen in DailyBarContext now reflects first RTH bar open, not the breakout bar open. - Log all 10 factor scores at signal acceptance for observability.
This commit is contained in:
@@ -20,6 +20,7 @@ namespace NT8.Core.Risk
|
||||
private double _dailyPnL;
|
||||
private double _maxDrawdown;
|
||||
private bool _tradingHalted;
|
||||
private double _configuredDailyLossLimit;
|
||||
private DateTime _lastUpdate = DateTime.UtcNow;
|
||||
private readonly Dictionary<string, double> _symbolExposure = new Dictionary<string, double>();
|
||||
|
||||
@@ -27,6 +28,15 @@ namespace NT8.Core.Risk
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_logger = logger;
|
||||
_configuredDailyLossLimit = 1000.0;
|
||||
}
|
||||
|
||||
public BasicRiskManager(ILogger logger, double dailyLossLimit)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (dailyLossLimit <= 0.0) throw new ArgumentException("dailyLossLimit must be positive", "dailyLossLimit");
|
||||
_logger = logger;
|
||||
_configuredDailyLossLimit = dailyLossLimit;
|
||||
}
|
||||
|
||||
public RiskDecision ValidateOrder(StrategyIntent intent, StrategyContext context, RiskConfig config)
|
||||
@@ -216,10 +226,8 @@ namespace NT8.Core.Risk
|
||||
|
||||
private void CheckEmergencyConditions(double dayPnL)
|
||||
{
|
||||
// Emergency halt if daily loss exceeds 90% of limit
|
||||
// Using a default limit of 1000 as this method doesn't have access to config
|
||||
// In Phase 1, this should be improved to use the actual config value
|
||||
if (dayPnL <= -(1000 * 0.9) && !_tradingHalted)
|
||||
// Emergency halt if daily loss exceeds 90% of configured limit
|
||||
if (dayPnL <= -(_configuredDailyLossLimit * 0.9) && !_tradingHalted)
|
||||
{
|
||||
_tradingHalted = true;
|
||||
_logger.LogCritical("Emergency halt triggered at 90% of daily loss limit: {0:C}", dayPnL);
|
||||
|
||||
Reference in New Issue
Block a user