== Component: setup_quality_detection.py ==
=== Purpose (Trading Context) ===
The Grader - This component answers: "How good is this trading setup?"
Think of it like a teacher grading an exam: Each setup is scored on 5 factors, penalties are applied for bad conditions, and a final grade (A+ to F) is assigned. The grade determines position size and whether we should trade at all.
Key Philosophy: Not all setups are equal. A+ setups get bigger positions. C/D/F setups are rejected by signal generation.
=== What It Does (Simple Terms) ===
1. Receives analyzed data from upstream components
2. Scores each setup on 5 weighted factors (0-100 each)
3. Applies penalties for adverse market conditions (creeper, MA struggle, etc.)
4. Caps score if A+ criteria not met
5. Assigns letter grade (A+ to F)
6. Recommends position size based on grade
=== Inputs ===
| Input |
Source |
What It Provides
|
| timeframe_analysis |
multi_timeframe_analysis.py |
Alignment score, aligned flag
|
| market_state |
market_state_analysis.py |
Creeper move, MA struggle, railroad trend, trend phase, institutional fight
|
| entry_data |
Calculated in main.py |
near_key_level, near_ma, clean_entry, risk_reward
|
| strategy_config |
Configuration |
Strategy ID
|
| timestamp |
Current bar |
Timestamp for logging
|
=== Outputs (SetupQualityResult) ===
| Field |
Type |
Description
|
| grade |
SetupQualityGrade |
A+, A, B, C, D, or F
|
| score |
float |
0-100 final score after all penalties
|
| factor_scores |
Dict |
Individual scores for each of 5 factors
|
| position_size |
int |
Recommended lots (1 or 2)
|
| risk_percent |
float |
Risk % based on grade
|
| can_auto_trade |
bool |
Only A+ and A are auto-tradeable
|
=== The 5-Factor Scoring System ===
Total Weight = 100% (must sum to exactly 1.0)
| Factor |
Weight |
What It Measures |
Calculation
|
| Timeframe Alignment |
30% |
Are all timeframes pointing same direction? |
alignment_score × 100
|
| Trend Strength |
20% |
Is trend healthy? |
100 - penalties + bonuses
|
| Entry Quality |
15% |
Is entry at a good spot? |
100 + bonuses - penalties
|
| Key Level Proximity |
20% |
Is price near important level? |
100 - 50 if not near key level
|
| Risk/Reward |
15% |
Is R:R acceptable? |
Lookup table (see below)
|
=== Risk/Reward Scoring Table ===
EXACT boundaries from specification:
| R:R Range |
Score |
Rating
|
| < 1.0 |
0 |
Unacceptable
|
| [1.0, 1.5) |
40 |
Poor
|
| [1.5, 2.0) |
70 |
Acceptable
|
| [2.0, 3.0) |
90 |
Good
|
| >= 3.0 |
100 |
Excellent
|
=== Penalties & Bonuses (Trend Strength Factor) ===
Applied to Factor 2: Trend Strength
| Condition |
Adjustment |
Trigger Field
|
| Creeper Move |
-50 |
is_creeper_move = True
|
| MA Struggle |
-30 |
price_ma_struggle = True
|
| No Two-Day Trend |
-30 |
has_two_day_trend = False
|
| Not Middle Phase |
-25 |
trend_phase ≠ MIDDLE
|
| Railroad Trend |
+15 |
is_railroad_trend = True
|
=== Penalties & Bonuses (Entry Quality Factor) ===
Applied to Factor 3: Entry Quality
| Condition |
Adjustment |
Trigger
|
| Near Key Level |
+10 |
entry_data['near_key_level'] = True
|
| Not Near MA |
-40 |
entry_data['near_ma'] = False
|
| Clean Entry |
+10 |
entry_data['clean_entry'] = True
|
=== Institutional Fight Penalty (Algorithm 4) ===
Philosophy: When institutions are battling each other, don't trade.
* Trigger: institutional_fight_in_progress = True
* Effect: Score × 0.7 (30% haircut)
* Applied AFTER weighted score calculation
=== A+ Criteria Enforcement (Algorithm 5) ===
Philosophy: A+ is earned, not given. Must meet ALL criteria.
To qualify for A+ (score >= 90):
1. All timeframes aligned (timeframe_analysis.aligned = True)
2. Entry near MA (entry_data['near_ma'] = True)
3. Has two-day trend (market_state.has_two_day_trend = True)
If ANY criterion fails: Score capped at 79 (forced to B grade)
=== Grade Thresholds (Algorithm 6) ===
| Grade |
Min Score |
Position Size |
Risk % |
Auto-Trade?
|
| A+ |
90 |
2 lots |
1.5% |
Yes
|
| A |
80 |
1 lot |
1.2% |
Yes
|
| B |
70 |
1 lot |
1.0% |
No
|
| C |
60 |
1 lot |
0.8% |
No
|
| D |
50 |
1 lot |
0.5% |
No
|
| F |
<50 |
1 lot |
0.3% |
No
|
Note: C/D/F grades are REJECTED by signal_generation (no trade taken).
=== Key Methods (For Developers) ===
| Method |
Purpose |
Critical Notes
|
| analyze() |
Main orchestration |
Runs all 6 algorithms in sequence
|
| _calculate_factor_scores() |
Calculate all 5 factors |
Returns Dict with 5 scores
|
| _calculate_trend_strength_score() |
Factor 2 with penalties/bonuses |
Most complex - many conditions
|
| _calculate_risk_reward_score() |
Factor 5 lookup table |
EXACT boundary comparisons
|
| _apply_institutional_fight_penalty() |
Algorithm 4: 0.7x multiplier |
Check institutional_fight_in_progress
|
| _enforce_a_plus_criteria() |
Algorithm 5: Cap at 79 if not qualified |
3 criteria must ALL pass
|
| _assign_setup_grade() |
Algorithm 6: Score → Grade |
Simple threshold comparison
|
| _calculate_position_sizing() |
Grade → lots, risk% |
TICKET-5: Realistic sizing
|
=== Configuration Constants ===
# Factor Weights (MUST sum to 1.0)
timeframe_alignment_weight = 0.30
trend_strength_weight = 0.20
entry_technique_weight = 0.15
key_level_proximity_weight = 0.20
risk_reward_weight = 0.15
# Penalties
creeper_move_penalty = -50
ma_struggle_penalty = -30
two_day_trend_penalty = -30
phase_mismatch_penalty = -25
ma_distance_penalty = -40
no_key_level_penalty = -50
institutional_fight_multiplier = 0.7
# Bonuses
railroad_trend_bonus = +15
key_level_bonus = +10
clean_entry_bonus = +10
# Grade Thresholds
a_plus_min_score = 90
a_min_score = 80
b_min_score = 70
c_min_score = 60
d_min_score = 50
=== Common Debugging Questions ===
Q: Why is grade capped at B (score 79) even though raw score is higher?
Check A+ criteria:
1. Is timeframe_analysis.aligned = True?
2. Is entry_data['near_ma'] = True?
3. Is market_state.has_two_day_trend = True?
If ANY is False → score capped at 79.
Q: Why is trend_strength score so low?
Check penalties applied:
* is_creeper_move = True? (-50)
* price_ma_struggle = True? (-30)
* has_two_day_trend = False? (-30)
* trend_phase ≠ MIDDLE? (-25)
Multiple penalties can stack!
Q: Why is position_size always 1 except for A+?
TICKET-5 fix: Realistic sizing for Rs 1 lakh capital.
Only A+ setups get 2 lots (premium setups).
Q: How do I trace which penalties were applied?
Check SetupQualityResult.penalties_applied list and analysis_comments.