Summary
The ATR/support-resistance trading levels in fast analysis frequently produce take-profit/stop-loss pairs where the reward distance is smaller than the risk distance (R/R < 1), and the computed risk_reward_ratio is never enforced or flagged anywhere.
Location
backend_api_python/app/services/market/technical_indicators.py (v5.0.17):
atr_stop_loss = current_price - (2 * atr)
suggested_stop_loss = max(atr_stop_loss, support_stop * 0.99) # picks the NEARER stop
atr_take_profit = current_price + (3 * atr)
suggested_take_profit = min(atr_take_profit, resistance_tp * 1.01) # picks the NEARER target
risk = current_price - suggested_stop_loss
reward = suggested_take_profit - current_price
"risk_reward_ratio": round(reward / risk, 2) if risk > 0 else 0,
When price trades near resistance (e.g. price_position ≈ 80), the take-profit gets pinned just above the nearby resistance while the stop keeps the full 2×ATR distance — R/R collapses below 1. This is asymmetric by construction: the stop takes the nearer anchor, the target also takes the nearer anchor.
Additionally, _finalize_trading_plan_for_decision in fast_analysis.py overwrites the LLM's chosen stop_loss/take_profit with these suggested levels whenever they exist, so every displayed plan uses this construction regardless of what the model proposed.
Production evidence
From a v5.0.17 deployment running hourly fast-analysis on 6 symbols (crypto + US stocks), 4 days, 518 completed analyses:
- 70% of trading plans had R/R < 1.0 (average 0.91, computed from each plan's entry/sl/tp)
- During a strong rally in the window (BTC +24%, ETH +33%, SOL +25%, HYPE +32%), signals were issued with price at the 77–81st percentile of the recent range
risk_reward_ratio shown alongside the plan can be < 1 with no warning to the user
Backtest experiments (important: the naive fix is harmful)
We replicated this construction as a fade-overbought short strategy and ran it through QuantDinger's own Strategy V2 backtest engine (BTC & ETH, 1D, 2024-09 → 2026-08, commission 0.04%, slippage 0.05%):
| Variant |
BTC |
ETH |
Trades |
| Current construction (baseline) |
−10.6% |
−43.9% |
12 / 9 |
| Naive fix: force R/R ≥ 1.2 by widening TP |
−30.5% (win rate 67% → 36%) |
−36.4% |
11 / 9 |
| Naive fix: block counter-trend entries when MA20>MA60 & price>MA60 |
0.0% (0 trades in 2 years) |
−27.8% |
0 / 2 |
(Small samples, n = 0–13 trades — directional, not statistically significant.)
The takeaway: simply widening the take-profit to enforce a floor made BTC three times worse, because the near resistance-cap was the only thing giving the construction its hit rate. Any remedy here should be backtested before shipping.
Suggestions
- Minimum: when the finalized plan implies R/R < 1, flag it in the response/UI (e.g.
rr_warning: true) instead of silently presenting it as a normal plan.
- Consider using the next resistance level (R2) when R1 is within ~2×ATR of price — but please validate with backtests first; our data suggests naive TP widening is counterproductive.
- Consider whether
_finalize_trading_plan_for_decision discarding the LLM's levels is intended — it makes the detailed prompt instructions for stop/target placement moot.
Happy to share the replay methodology or backtest code if useful.
Summary
The ATR/support-resistance trading levels in fast analysis frequently produce take-profit/stop-loss pairs where the reward distance is smaller than the risk distance (R/R < 1), and the computed
risk_reward_ratiois never enforced or flagged anywhere.Location
backend_api_python/app/services/market/technical_indicators.py(v5.0.17):When price trades near resistance (e.g.
price_position≈ 80), the take-profit gets pinned just above the nearby resistance while the stop keeps the full 2×ATR distance — R/R collapses below 1. This is asymmetric by construction: the stop takes the nearer anchor, the target also takes the nearer anchor.Additionally,
_finalize_trading_plan_for_decisioninfast_analysis.pyoverwrites the LLM's chosen stop_loss/take_profit with these suggested levels whenever they exist, so every displayed plan uses this construction regardless of what the model proposed.Production evidence
From a v5.0.17 deployment running hourly fast-analysis on 6 symbols (crypto + US stocks), 4 days, 518 completed analyses:
risk_reward_ratioshown alongside the plan can be < 1 with no warning to the userBacktest experiments (important: the naive fix is harmful)
We replicated this construction as a fade-overbought short strategy and ran it through QuantDinger's own Strategy V2 backtest engine (BTC & ETH, 1D, 2024-09 → 2026-08, commission 0.04%, slippage 0.05%):
(Small samples, n = 0–13 trades — directional, not statistically significant.)
The takeaway: simply widening the take-profit to enforce a floor made BTC three times worse, because the near resistance-cap was the only thing giving the construction its hit rate. Any remedy here should be backtested before shipping.
Suggestions
rr_warning: true) instead of silently presenting it as a normal plan._finalize_trading_plan_for_decisiondiscarding the LLM's levels is intended — it makes the detailed prompt instructions for stop/target placement moot.Happy to share the replay methodology or backtest code if useful.