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:
@@ -426,6 +426,46 @@ namespace NinjaTrader.NinjaScript.Strategies
|
||||
_executionAdapter.ProcessExecution(orderId, executionId, price, quantity, time);
|
||||
}
|
||||
|
||||
protected override void OnPositionUpdate(
|
||||
Position position,
|
||||
double averagePrice,
|
||||
int quantity,
|
||||
MarketPosition marketPosition)
|
||||
{
|
||||
if (!_sdkInitialized || _riskManager == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
double dayPnL = 0.0;
|
||||
if (Account != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
dayPnL = Account.Get(AccountItem.GainLoss, Currency.UsDollar);
|
||||
}
|
||||
catch
|
||||
{
|
||||
dayPnL = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
_riskManager.OnPnLUpdate(dayPnL, dayPnL);
|
||||
PortfolioRiskManager.Instance.ReportPnL(Name, dayPnL);
|
||||
|
||||
if (EnableVerboseLogging)
|
||||
Print(string.Format("[SDK] P&L update: DayPnL={0:C} Position={1} Qty={2}",
|
||||
dayPnL, marketPosition, quantity));
|
||||
|
||||
FileLog(string.Format("PNL_UPDATE DayPnL={0:C} Position={1} Qty={2}",
|
||||
dayPnL, marketPosition, quantity));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Print(string.Format("[SDK] OnPositionUpdate error: {0}", ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles broker connection status changes. Halts new orders on disconnect,
|
||||
/// logs reconnect, and resets the connection flag when restored.
|
||||
@@ -571,7 +611,7 @@ namespace NinjaTrader.NinjaScript.Strategies
|
||||
_riskConfig,
|
||||
_sizingConfig);
|
||||
|
||||
_riskManager = new BasicRiskManager(_logger);
|
||||
_riskManager = new BasicRiskManager(_logger, DailyLossLimit);
|
||||
_positionSizer = new BasicPositionSizer(_logger);
|
||||
_circuitBreaker = new ExecutionCircuitBreaker(
|
||||
_logger,
|
||||
@@ -842,15 +882,25 @@ namespace NinjaTrader.NinjaScript.Strategies
|
||||
FileLog(string.Format("SIGNAL {0} | Grade={1} | Score={2}", intent.Side, grade, score));
|
||||
if (!string.IsNullOrEmpty(factors))
|
||||
FileLog(string.Format(" Factors: {0}", factors));
|
||||
FileLog(string.Format("SUBMIT {0} {1} @ Market | Stop={2} Target={3}",
|
||||
FileLog(string.Format("SUBMIT {0} {1} @ Market | Stop={2} Target={3}{4}",
|
||||
intent.Side,
|
||||
request.Quantity,
|
||||
intent.StopTicks,
|
||||
intent.TargetTicks));
|
||||
intent.TargetTicks,
|
||||
intent.Metadata != null && intent.Metadata.ContainsKey("dynamic_target_ticks") ? " [dynamic]" : ""));
|
||||
}
|
||||
|
||||
_executionAdapter.SubmitOrder(request, orderName);
|
||||
|
||||
// Register stop and target BEFORE submitting the entry order.
|
||||
// NT8 requires stop/target to be pre-registered to the signal name
|
||||
// so they are applied correctly in both backtest and live/SIM modes.
|
||||
if (intent.StopTicks > 0)
|
||||
SetStopLoss(orderName, CalculationMode.Ticks, (int)intent.StopTicks, false);
|
||||
|
||||
if (intent.TargetTicks.HasValue && intent.TargetTicks.Value > 0)
|
||||
SetProfitTarget(orderName, CalculationMode.Ticks, (int)intent.TargetTicks.Value);
|
||||
|
||||
if (request.Side == OmsOrderSide.Buy)
|
||||
{
|
||||
if (request.Type == OmsOrderType.Market)
|
||||
@@ -870,12 +920,6 @@ namespace NinjaTrader.NinjaScript.Strategies
|
||||
EnterShortStopMarket(request.Quantity, (double)request.StopPrice.Value, orderName);
|
||||
}
|
||||
|
||||
if (intent.StopTicks > 0)
|
||||
SetStopLoss(orderName, CalculationMode.Ticks, (int)intent.StopTicks, false);
|
||||
|
||||
if (intent.TargetTicks.HasValue && intent.TargetTicks.Value > 0)
|
||||
SetProfitTarget(orderName, CalculationMode.Ticks, (int)intent.TargetTicks.Value);
|
||||
|
||||
if (_circuitBreaker != null)
|
||||
_circuitBreaker.OnSuccess();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user