Jump to content

Alpha Research: Difference between revisions

From PlusEV Wiki Page
No edit summary
No edit summary
Line 25: Line 25:
'''Branch''': <code>rikk_mtf_backtest001</code> | '''Commit''': <code>68dae212</code>
'''Branch''': <code>rikk_mtf_backtest001</code> | '''Commit''': <code>68dae212</code>


{{quote|In trading systems, empirical results > theoretical understanding. If the backtest shows it works, we ship it.}}
<blockquote>''In trading systems, empirical results > theoretical understanding. If the backtest shows it works, we ship it.''</blockquote>


----
----
Line 70: Line 70:


=== Code Implementation ===
=== Code Implementation ===
<syntaxhighlight lang="python">
<source lang="python">
# File: signal_generation_trade_management.py:99-109
# File: signal_generation_trade_management.py:99-109
enable_probability_zone_filter: bool = True
enable_probability_zone_filter: bool = True
probability_zone_swing_lookback: int = 20    # Bars to find swing H/L
probability_zone_swing_lookback: int = 20    # Bars to find swing H/L
probability_zone_min_range: float = 20.0    # Min range for valid zone
probability_zone_min_range: float = 20.0    # Min range for valid zone
</syntaxhighlight>
</source>


----
----
Line 103: Line 103:


=== Code Implementation ===
=== Code Implementation ===
<syntaxhighlight lang="python">
<source lang="python">
# File: signal_generation_trade_management.py:108
# File: signal_generation_trade_management.py:108
crash_bar_multiplier: float = 2.0  # Bar must be 2x average for crash detection
crash_bar_multiplier: float = 2.0  # Bar must be 2x average for crash detection
</syntaxhighlight>
</source>


----
----
Line 185: Line 185:


=== Code Implementation ===
=== Code Implementation ===
<syntaxhighlight lang="python">
<source lang="python">
# File: signal_generation_trade_management.py:107
# File: signal_generation_trade_management.py:107
three_finger_spread_threshold: float = 0.02  # 2% min spread for detection
three_finger_spread_threshold: float = 0.02  # 2% min spread for detection
</syntaxhighlight>
</source>


----
----
Line 211: Line 211:
=== MA is a ZONE, Not a Line ===
=== MA is a ZONE, Not a Line ===


{{quote|The MA is a zone, not a thin line. Don't be exact with this.}}
<blockquote>''The MA is a zone, not a thin line. Don't be exact with this.''</blockquote>


<syntaxhighlight lang="python">
<source lang="python">
# File: signal_generation_trade_management.py:68
# File: signal_generation_trade_management.py:68
ma_buffer_points: float = 25.0  # 21 MA zone width (not a thin line)
ma_buffer_points: float = 25.0  # 21 MA zone width (not a thin line)
</syntaxhighlight>
</source>


=== Fab Four Tightness = Explosive Potential ===
=== Fab Four Tightness = Explosive Potential ===
Line 263: Line 263:


=== Code Implementation ===
=== Code Implementation ===
<syntaxhighlight lang="python">
<source lang="python">
# File: setup_quality_detection.py:43-48
# File: setup_quality_detection.py:43-48
timeframe_alignment_weight: float = 0.30  # 30% of setup quality score
timeframe_alignment_weight: float = 0.30  # 30% of setup quality score
</syntaxhighlight>
</source>


----
----
Line 284: Line 284:
=== The Warning ===
=== The Warning ===


{{quote|Bar-by-bar will knock you out of riches. If there is one stopout that is going to knock you out of the biggest gains of your life, it's going to be bar-by-bar.}}
<blockquote>''Bar-by-bar will knock you out of riches. If there is one stopout that is going to knock you out of the biggest gains of your life, it's going to be bar-by-bar.''</blockquote>


'''Use bar-by-bar ONLY when:'''
'''Use bar-by-bar ONLY when:'''
Line 319: Line 319:
</pre>
</pre>


{{quote|The real goal is to get your stop beyond the Fab Four helping zone.}}
<blockquote>''The real goal is to get your stop beyond the Fab Four helping zone.''</blockquote>


=== Code Implementation ===
=== Code Implementation ===
<syntaxhighlight lang="python">
<source lang="python">
# File: signal_generation_trade_management.py:59-60
# File: signal_generation_trade_management.py:59-60
min_stop_distance: float = 40.0    # TICKET-13: Increased from 20
min_stop_distance: float = 40.0    # TICKET-13: Increased from 20
default_stop_distance: float = 40.0  # Minimum buffer for price noise
default_stop_distance: float = 40.0  # Minimum buffer for price noise
</syntaxhighlight>
</source>


----
----
Line 355: Line 355:


=== Code Implementation ===
=== Code Implementation ===
<syntaxhighlight lang="python">
<source lang="python">
# File: signal_generation_trade_management.py:80-81
# File: signal_generation_trade_management.py:80-81
bos_structure_lookback: int = 10  # TICKET-11: Extended for BOS stops
bos_structure_lookback: int = 10  # TICKET-11: Extended for BOS stops
bos_stop_buffer_points: float = 5.0  # Buffer for structure-based stops
bos_stop_buffer_points: float = 5.0  # Buffer for structure-based stops
</syntaxhighlight>
</source>


----
----
Line 380: Line 380:
=== Key Rule: Don't Wait for Bar to Complete ===
=== Key Rule: Don't Wait for Bar to Complete ===


{{quote|As soon as the red bar crosses below the green, boom boom boom boom boom. You're in.}}
<blockquote>''As soon as the red bar crosses below the green, boom boom boom boom boom. You're in.''</blockquote>


----
----
Line 388: Line 388:
=== The Two-Bar Rule ===
=== The Two-Bar Rule ===


{{quote|Take profits TWO bars after the opposite color, NOT one bar.}}
<blockquote>''Take profits TWO bars after the opposite color, NOT one bar.''</blockquote>


<pre>
<pre>
Line 412: Line 412:
</pre>
</pre>


{{quote|The first lot is your REAL trade. The second lot is the cherry on top.}}
<blockquote>''The first lot is your REAL trade. The second lot is the cherry on top.''</blockquote>


=== Code Implementation ===
=== Code Implementation ===
<syntaxhighlight lang="python">
<source lang="python">
# File: signal_generation_trade_management.py:111-118
# File: signal_generation_trade_management.py:111-118
enable_color_change_filter: bool = False    # DISABLED - too restrictive
enable_color_change_filter: bool = False    # DISABLED - too restrictive
color_change_ma_proximity: float = 20.0      # Points to consider "near" MA
color_change_ma_proximity: float = 20.0      # Points to consider "near" MA
require_ma_bounce: bool = False              # Don't require strict MA bounce
require_ma_bounce: bool = False              # Don't require strict MA bounce
</syntaxhighlight>
</source>


----
----
Line 648: Line 648:
'''Problem''': Previous sizing = 100-200 lots = Rs 5.7 Crore exposure on Rs 1 lakh capital (5700x!)
'''Problem''': Previous sizing = 100-200 lots = Rs 5.7 Crore exposure on Rs 1 lakh capital (5700x!)


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE (service/backtest):
# BEFORE (service/backtest):
multipliers = {
multipliers = {
Line 666: Line 666:
     SetupQualityGrade.F: 1
     SetupQualityGrade.F: 1
}
}
</syntaxhighlight>
</source>


----
----
Line 675: Line 675:
'''Problem''': Slippage moved entry but stop/target stayed fixed = corrupted R:R ratio
'''Problem''': Slippage moved entry but stop/target stayed fixed = corrupted R:R ratio


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE: Stop and target not adjusted after slippage
# BEFORE: Stop and target not adjusted after slippage
actual_execution_price = execution_price + market_slippage  # Entry moved
actual_execution_price = execution_price + market_slippage  # Entry moved
Line 698: Line 698:
     adjusted_stop_loss = signal.stop_loss_price - market_slippage
     adjusted_stop_loss = signal.stop_loss_price - market_slippage
     adjusted_take_profit = signal.take_profit_price - market_slippage
     adjusted_take_profit = signal.take_profit_price - market_slippage
</syntaxhighlight>
</source>


----
----
Line 707: Line 707:
'''Problem''': CTT was 0.05% (5x too high!). Dhan broker calculates Rs 52 on Rs 5.2L = 0.01%
'''Problem''': CTT was 0.05% (5x too high!). Dhan broker calculates Rs 52 on Rs 5.2L = 0.01%


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE:
# BEFORE:
transaction_tax_rate: float = 0.000500  # 0.05% - WRONG!
transaction_tax_rate: float = 0.000500  # 0.05% - WRONG!
Line 716: Line 716:
# Dhan verified: CTT Rs 52 on Rs 5,20,000 sell value = 0.01%
# Dhan verified: CTT Rs 52 on Rs 5,20,000 sell value = 0.01%
transaction_tax_rate: float = 0.000050  # 0.005% per leg × 2 = 0.01% total
transaction_tax_rate: float = 0.000050  # 0.005% per leg × 2 = 0.01% total
</syntaxhighlight>
</source>


----
----
Line 725: Line 725:
'''Problem''': 100 lots × 0.1 = 10 pts slippage (excessive!)
'''Problem''': 100 lots × 0.1 = 10 pts slippage (excessive!)


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE: No cap on market impact
# BEFORE: No cap on market impact
size_impact = signal.position_size * self.config.market_impact_factor
size_impact = signal.position_size * self.config.market_impact_factor
Line 740: Line 740:
#  - volatility: 0.5 pts
#  - volatility: 0.5 pts
#  - total: ~1.6 pts (realistic for MCX crude)
#  - total: ~1.6 pts (realistic for MCX crude)
</syntaxhighlight>
</source>


----
----
Line 749: Line 749:
'''Problem''': Entry technique logic didn't match strategy_engine.py priority order
'''Problem''': Entry technique logic didn't match strategy_engine.py priority order


<syntaxhighlight lang="python">
<source lang="python">
# COMPLETE REWRITE of _determine_entry_technique():
# COMPLETE REWRITE of _determine_entry_technique():
# BEFORE: Random priority order, creeper before BOS, missing key level checks
# BEFORE: Random priority order, creeper before BOS, missing key level checks
Line 761: Line 761:
# PRIORITY 6: Railroad trend → GREEN_BAR_AFTER_PULLBACK / RED_BAR_AFTER_RALLY
# PRIORITY 6: Railroad trend → GREEN_BAR_AFTER_PULLBACK / RED_BAR_AFTER_RALLY
# PRIORITY 7: Fallback → NEAR_MA
# PRIORITY 7: Fallback → NEAR_MA
</syntaxhighlight>
</source>


----
----
Line 770: Line 770:
'''Problem''': 5-bar lookback + no buffer = stop too close in trending markets = 66.7% stop rate
'''Problem''': 5-bar lookback + no buffer = stop too close in trending markets = 66.7% stop rate


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE:
# BEFORE:
structure_lookback: int = 5  # Too short for BOS
structure_lookback: int = 5  # Too short for BOS
Line 777: Line 777:
bos_structure_lookback: int = 10    # Extended lookback for BOS stops
bos_structure_lookback: int = 10    # Extended lookback for BOS stops
bos_stop_buffer_points: float = 5.0  # Buffer below/above structure
bos_stop_buffer_points: float = 5.0  # Buffer below/above structure
</syntaxhighlight>
</source>


----
----
Line 786: Line 786:
'''Problem''': Certain hours consistently lose money
'''Problem''': Certain hours consistently lose money


<syntaxhighlight lang="python">
<source lang="python">
# NEW CONFIGURATION:
# NEW CONFIGURATION:
enable_hour_filter: bool = True
enable_hour_filter: bool = True
Line 800: Line 800:
     if current_hour in self.config.blocked_hours:
     if current_hour in self.config.blocked_hours:
         return None  # No signal during blocked hours
         return None  # No signal during blocked hours
</syntaxhighlight>
</source>


----
----
Line 809: Line 809:
'''Problem''': 20pt stops hit too frequently due to normal price noise
'''Problem''': 20pt stops hit too frequently due to normal price noise


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE:
# BEFORE:
default_stop_distance: float = 20.000000
default_stop_distance: float = 20.000000
Line 820: Line 820:
# TICKET-13 FIX: ENFORCE MINIMUM STOP DISTANCE (40 POINTS)
# TICKET-13 FIX: ENFORCE MINIMUM STOP DISTANCE (40 POINTS)
stop_distance = max(calculated_stop_distance, self.config.min_stop_distance)
stop_distance = max(calculated_stop_distance, self.config.min_stop_distance)
</syntaxhighlight>
</source>


----
----
Line 829: Line 829:
'''Problem''': No way to track current trailing stop position vs original
'''Problem''': No way to track current trailing stop position vs original


<syntaxhighlight lang="python">
<source lang="python">
# NEW FIELD in Trade dataclass:
# NEW FIELD in Trade dataclass:
current_stop_price: Optional[float] = None  # Current trailing stop (moves with price)
current_stop_price: Optional[float] = None  # Current trailing stop (moves with price)
Line 858: Line 858:
             if new_stop > trade.current_stop_price:
             if new_stop > trade.current_stop_price:
                 trade.current_stop_price = new_stop  # Only move UP
                 trade.current_stop_price = new_stop  # Only move UP
</syntaxhighlight>
</source>


----
----
Line 867: Line 867:
'''Problem''': Needed automatic breakeven move when in profit
'''Problem''': Needed automatic breakeven move when in profit


<syntaxhighlight lang="python">
<source lang="python">
# NEW CONFIGURATION:
# NEW CONFIGURATION:
enable_breakeven_stop: bool = True
enable_breakeven_stop: bool = True
Line 875: Line 875:
# Tested 10pt activation but cut winners too short (26% WR vs 49%)
# Tested 10pt activation but cut winners too short (26% WR vs 49%)
# 25pt activation is the sweet spot
# 25pt activation is the sweet spot
</syntaxhighlight>
</source>


----
----
Line 884: Line 884:
'''Problem''': Previous implementation blocked creeper signals entirely (too aggressive)
'''Problem''': Previous implementation blocked creeper signals entirely (too aggressive)


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE: Creeper signals blocked with return None
# BEFORE: Creeper signals blocked with return None


Line 894: Line 894:
# NEAR_MA technique used in _determine_entry_technique()
# NEAR_MA technique used in _determine_entry_technique()
# Let the scoring system decide rather than blocking outright
# Let the scoring system decide rather than blocking outright
</syntaxhighlight>
</source>


----
----
Line 903: Line 903:
'''Problem''': Trades against MA21 slope direction had poor performance
'''Problem''': Trades against MA21 slope direction had poor performance


<syntaxhighlight lang="python">
<source lang="python">
# CONFIGURATION:
# CONFIGURATION:
enable_ma_direction_filter: bool = True
enable_ma_direction_filter: bool = True
Line 926: Line 926:
# +15% bonus if trade direction aligns with MA21 slope
# +15% bonus if trade direction aligns with MA21 slope
# -10% penalty if trade direction against MA21 slope
# -10% penalty if trade direction against MA21 slope
</syntaxhighlight>
</source>


----
----
Line 935: Line 935:
'''Problem''': Needed trade_philosophy.pdf concepts in code
'''Problem''': Needed trade_philosophy.pdf concepts in code


<syntaxhighlight lang="python">
<source lang="python">
# NEW CONFIGURATION (Probability Zones):
# NEW CONFIGURATION (Probability Zones):
enable_probability_zone_filter: bool = True
enable_probability_zone_filter: bool = True
Line 963: Line 963:
         true_ranges.append(tr)
         true_ranges.append(tr)
     self.current_atr = sum(true_ranges) / len(true_ranges)
     self.current_atr = sum(true_ranges) / len(true_ranges)
</syntaxhighlight>
</source>


----
----
Line 972: Line 972:
'''Problem''': color_change.pdf patterns too restrictive for automation
'''Problem''': color_change.pdf patterns too restrictive for automation


<syntaxhighlight lang="python">
<source lang="python">
# CONFIGURATION (disabled):
# CONFIGURATION (disabled):
enable_color_change_filter: bool = False  # DISABLED - too restrictive
enable_color_change_filter: bool = False  # DISABLED - too restrictive
Line 983: Line 983:
# - LONG: Green bar sweeps BELOW red bar low + bounce from 21 MA
# - LONG: Green bar sweeps BELOW red bar low + bounce from 21 MA
# - SHORT: Red bar sweeps ABOVE green bar high + rejection from 21 MA
# - SHORT: Red bar sweeps ABOVE green bar high + rejection from 21 MA
</syntaxhighlight>
</source>


----
----
Line 992: Line 992:
'''Problem''': strategy_engine.py bug - uses wrong entry technique for creeper moves
'''Problem''': strategy_engine.py bug - uses wrong entry technique for creeper moves


<syntaxhighlight lang="python">
<source lang="python">
# STRATEGY ENGINE BUG FOUND:
# STRATEGY ENGINE BUG FOUND:
# backtesting_standalone/src/strategy_engine.py lines 3338-3380
# backtesting_standalone/src/strategy_engine.py lines 3338-3380
Line 1,003: Line 1,003:
     # But uses NEAR_MA as technique (NOT green_bar/red_bar!)
     # But uses NEAR_MA as technique (NOT green_bar/red_bar!)
     return EntryTechnique.NEAR_MA  # Strategy engine fallback
     return EntryTechnique.NEAR_MA  # Strategy engine fallback
</syntaxhighlight>
</source>


----
----
Line 1,012: Line 1,012:
'''Problem''': Creeper threshold 0.5% calibrated for 1H bars (~0.8-1.2% range), but code used 5MIN (~0.16% range) = 98.9% false positives!
'''Problem''': Creeper threshold 0.5% calibrated for 1H bars (~0.8-1.2% range), but code used 5MIN (~0.16% range) = 98.9% false positives!


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE:
# BEFORE:
required_tf = TimeframeValue.FIVE_MIN
required_tf = TimeframeValue.FIVE_MIN
Line 1,039: Line 1,039:
     """
     """
     primary_tf = TimeframeValue.ONE_HOUR  # Was FIVE_MIN
     primary_tf = TimeframeValue.ONE_HOUR  # Was FIVE_MIN
</syntaxhighlight>
</source>


----
----
Line 1,048: Line 1,048:
'''Source''': Fab Four concept - "MA is a zone, not a thin line"
'''Source''': Fab Four concept - "MA is a zone, not a thin line"


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE:
# BEFORE:
ma_buffer_points: float = 5.000000  # Too tight!
ma_buffer_points: float = 5.000000  # Too tight!
Line 1,055: Line 1,055:
# PDF-FIX: MA is a "zone, not a thin line" (Fab Four) - use wider buffer
# PDF-FIX: MA is a "zone, not a thin line" (Fab Four) - use wider buffer
ma_buffer_points: float = 25.000000  # 21 MA zone width
ma_buffer_points: float = 25.000000  # 21 MA zone width
</syntaxhighlight>
</source>


----
----
Line 1,064: Line 1,064:
'''Problem''': Old method used strategy.entry_exit_settings with FIXED_POINTS, ATR_MULTIPLE, etc. PDF philosophy uses 50% of prior move.
'''Problem''': Old method used strategy.entry_exit_settings with FIXED_POINTS, ATR_MULTIPLE, etc. PDF philosophy uses 50% of prior move.


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE: Used strategy config with multiple methods
# BEFORE: Used strategy config with multiple methods
def _calculate_take_profit(self, strategy, entry_price, stop_loss_price, direction):
def _calculate_take_profit(self, strategy, entry_price, stop_loss_price, direction):
Line 1,098: Line 1,098:
     risk_distance = abs(entry_price - stop_loss_price)
     risk_distance = abs(entry_price - stop_loss_price)
     return entry_price + (risk_distance * 2)
     return entry_price + (risk_distance * 2)
</syntaxhighlight>
</source>


----
----
Line 1,107: Line 1,107:
'''Logic''': In sideways market at top zone, big RED bar breaking below 21 MA overrides LONG direction to SHORT
'''Logic''': In sideways market at top zone, big RED bar breaking below 21 MA overrides LONG direction to SHORT


<syntaxhighlight lang="python">
<source lang="python">
# NEW CODE: Crash SHORT detection within probability zone filter
# NEW CODE: Crash SHORT detection within probability zone filter
# Per PDF: In top third, big RED bar breaking 21 MA = SHORT signal
# Per PDF: In top third, big RED bar breaking 21 MA = SHORT signal
Line 1,123: Line 1,123:
     direction = Direction.SHORT
     direction = Direction.SHORT
     is_crash_short = True  # Flag to skip color change filter
     is_crash_short = True  # Flag to skip color change filter
</syntaxhighlight>
</source>


----
----
Line 1,132: Line 1,132:
'''Problem''': Old code placed stop relative to MA value. New code uses structure low/high.
'''Problem''': Old code placed stop relative to MA value. New code uses structure low/high.


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE: Stop below/above MA value
# BEFORE: Stop below/above MA value
if entry_technique == EntryTechnique.NEAR_MA_LONG:
if entry_technique == EntryTechnique.NEAR_MA_LONG:
Line 1,153: Line 1,153:
         if stop_loss >= entry_price:
         if stop_loss >= entry_price:
             stop_loss = entry_price - self.config.default_stop_distance
             stop_loss = entry_price - self.config.default_stop_distance
</syntaxhighlight>
</source>


----
----
Line 1,162: Line 1,162:
'''Problem''': Grade assigned from capped original score instead of adjusted score
'''Problem''': Grade assigned from capped original score instead of adjusted score


<syntaxhighlight lang="python">
<source lang="python">
# BEFORE:
# BEFORE:
setup_quality=setup_quality.grade,    # Grade from CAPPED original score (79)
setup_quality=setup_quality.grade,    # Grade from CAPPED original score (79)
Line 1,181: Line 1,181:
     elif score >= 50: return SetupQualityGrade.D
     elif score >= 50: return SetupQualityGrade.D
     else: return SetupQualityGrade.F
     else: return SetupQualityGrade.F
</syntaxhighlight>
</source>


----
----
Line 1,190: Line 1,190:


=== Enums Defined ===
=== Enums Defined ===
<syntaxhighlight lang="python">
<source lang="python">
class ProbabilityZone(Enum):
class ProbabilityZone(Enum):
     TOP_THIRD = "top_third"          # 80% continuation probability
     TOP_THIRD = "top_third"          # 80% continuation probability
Line 1,214: Line 1,214:
     BEARISH_REVERSAL = "bearish_reversal"  # Red bar takes out green bar low
     BEARISH_REVERSAL = "bearish_reversal"  # Red bar takes out green bar low
     NO_PATTERN = "no_pattern"
     NO_PATTERN = "no_pattern"
</syntaxhighlight>
</source>


=== Key Classes ===
=== Key Classes ===
Line 1,224: Line 1,224:


=== Configuration Defaults ===
=== Configuration Defaults ===
<syntaxhighlight lang="python">
<source lang="python">
@dataclass
@dataclass
class ProbabilityZoneConfig:
class ProbabilityZoneConfig:
Line 1,235: Line 1,235:
     crash_bar_multiplier: float = 2.0      # Bar > 2x avg = crash
     crash_bar_multiplier: float = 2.0      # Bar > 2x avg = crash
     three_finger_min_spread_pct: float = 0.02  # 2% spread threshold
     three_finger_min_spread_pct: float = 0.02  # 2% spread threshold
</syntaxhighlight>
</source>


----
----
Line 1,249: Line 1,249:
# '''Mixed timestamp format''' - Use <code>format='mixed'</code> for pandas parsing
# '''Mixed timestamp format''' - Use <code>format='mixed'</code> for pandas parsing


<syntaxhighlight lang="python">
<source lang="python">
# Date column alias:
# Date column alias:
if 'date' in source_df.columns and 'timestamp' not in source_df.columns:
if 'date' in source_df.columns and 'timestamp' not in source_df.columns:
Line 1,262: Line 1,262:
# Mixed timestamp parsing:
# Mixed timestamp parsing:
pd.to_datetime(df['timestamp'], format='mixed')
pd.to_datetime(df['timestamp'], format='mixed')
</syntaxhighlight>
</source>


----
----
Line 1,274: Line 1,274:
# '''Emoji removal''' - Console output cleanup
# '''Emoji removal''' - Console output cleanup


<syntaxhighlight lang="python">
<source lang="python">
# TICKET-12: Hour Filter configuration:
# TICKET-12: Hour Filter configuration:
enable_hour_filter=strategy_config.get('enable_hour_filter', False),
enable_hour_filter=strategy_config.get('enable_hour_filter', False),
Line 1,281: Line 1,281:
print(f"  TICKET-12 Hour Filter: Enabled={signal_generator_config.enable_hour_filter}, "
print(f"  TICKET-12 Hour Filter: Enabled={signal_generator_config.enable_hour_filter}, "
       f"Blocked Hours={signal_generator_config.blocked_hours}")
       f"Blocked Hours={signal_generator_config.blocked_hours}")
</syntaxhighlight>
</source>


----
----

Revision as of 21:37, 4 January 2026

Alpha Research: MCX Crude Oil MA21 Strategy

Single Source of Truth for the PlusEV Trading System


Quick Reference: Backtest Proof

Metric Value Notes
Total P&L Rs +25,48,101 19-month validation period
Win Rate 57.6% Above 55% threshold
Profit Factor 1.20 Risk-adjusted returns
Total Trades 7,534 Statistical significance
Initial Capital Rs 1,00,000 Starting portfolio
Final Capital Rs 26,48,101 2548% return

Branch: rikk_mtf_backtest001 | Commit: 68dae212

In trading systems, empirical results > theoretical understanding. If the backtest shows it works, we ship it.


Part 1: Core Trading Philosophy

1.1 Foundational Principles

Simple systems outperform complex ones.
Market behavior is probabilistic, not predictive.
The goal is positioning with asymmetric probabilities, not prediction.

The Asymmetric Probability Edge

When odds are low on one outcome, the opposite side usually carries high odds:

  • If new high probability drops to 15%, then 85% odds favor reversal
  • We position ourselves on the high-probability side

1.2 Probability Zones (Halves & Thirds)

Every large move is divided into halves and thirds, creating probability zones.

Odds of Continuation After Pullback

┌─────────────────────────────────────────────────────┐
│  SWING HIGH                                         │
├─────────────────────────────────────────────────────┤
│  TOP THIRD        →  ~80% chance of new high        │  ← IDEAL SHORT ZONE
├─────────────────────────────────────────────────────┤
│  TOP HALF         →  ~65% chance of new high        │
├─────────────────────────────────────────────────────┤
│  BOTTOM HALF      →  ~35% chance of new high        │
├─────────────────────────────────────────────────────┤
│  BOTTOM THIRD     →  ~15% chance of new high        │  ← IDEAL LONG ZONE
├─────────────────────────────────────────────────────┤
│  SWING LOW                                          │
└─────────────────────────────────────────────────────┘

Code Implementation

<source lang="python">

  1. File: signal_generation_trade_management.py:99-109

enable_probability_zone_filter: bool = True probability_zone_swing_lookback: int = 20 # Bars to find swing H/L probability_zone_min_range: float = 20.0 # Min range for valid zone </source>


1.3 The Crash Play (Core Strategy)

What is a Crash Bar?

  • Much larger than recent bars
  • Fast, violent, elongated movement
  • Indicates a structural break

The Crash Play Logic

1. Identify crash bar (bar > 2x average size)
2. Divide it into halves and thirds
3. Watch for bounce INTO these zones
4. Enter when:
   - Color change confirms (red overtakes green), OR
   - Price reaches upper zones

Key Statistics

  • After a crash, bounces have only ~15% odds of reclaiming highs
  • ~85% odds favor continuation lower
  • Bounces after crashes are statistically SHORT opportunities

Code Implementation

<source lang="python">

  1. File: signal_generation_trade_management.py:108

crash_bar_multiplier: float = 2.0 # Bar must be 2x average for crash detection </source>


1.4 Pullback vs Collapse (Critical Distinction)

Healthy Pullback (Tradeable)

Characteristic Description
Angle 45-degree drifting decline, NOT vertical
Bars No violent or oversized red bars
Depth Holds above halfway point of prior run
Confirmation Color change (green overtakes red)

Interpretation: Pullbacks are rests, not reversals. Odds favor continuation.

Collapse (NOT Tradeable)

Characteristic Description
Angle Vertical, elongated, violent first drop
Depth Breaks deeply into or below prior run
Momentum Abrupt and forceful

Interpretation: Indicates institutional selling. Bounces are sucker plays.


1.5 Identifying Market Tops (4 Characteristics)

Major tops usually exhibit at least 2 of these 4 characteristics:

1. Three-to-Five Leg Run-Up

Markets top between leg 3 and leg 5.
- Buy: legs 1-2
- Ride: leg 3
- Take profits: legs 4-5
- Buying late (leg 4-5) = large downside vs small upside

2. Vertical Acceleration in Final Leg

If the last leg is STEEPER than prior legs → likely final leg
The most vertical leg is usually the top.

3. Exhaustion Bar

Final bar of final leg is:
- Larger than recent bars
- Often the largest bar of entire run
= Bulls deploy all remaining buying power
= Market becomes top-heavy and vulnerable

4. Three-Finger Spread (Dual Space)

Large separation between:
- Price
- 21-period MA
- 200-period MA

= Many traders holding large unrealized profits
= Any red bar can trigger mass profit-taking
= Creates fast, violent declines

Code Implementation

<source lang="python">

  1. File: signal_generation_trade_management.py:107

three_finger_spread_threshold: float = 0.02 # 2% min spread for detection </source>


Part 2: Entry Methodology

2.1 The Fab Four Concept

The Fab Four defines the key reference points for entries and stops:

┌─────────────────────────────────────────────────────┐
│  FAB FOUR ELEMENTS                                  │
├─────────────────────────────────────────────────────┤
│  1. Previous Day High/Low (PDHL)                    │
│  2. 21-Period Moving Average                        │
│  3. 200-Period Moving Average                       │
│  4. Yesterday's Close                               │
└─────────────────────────────────────────────────────┘

MA is a ZONE, Not a Line

The MA is a zone, not a thin line. Don't be exact with this.

<source lang="python">

  1. File: signal_generation_trade_management.py:68

ma_buffer_points: float = 25.0 # 21 MA zone width (not a thin line) </source>

Fab Four Tightness = Explosive Potential

When the Fab Four elements are tight together:

  • Indicates compressed energy
  • Expect powerful move (up or down)
  • Best trades come from narrowness

2.2 Entry Position Hierarchy

Best Entry Positions

FOR SHORTS:
┌─────────────────────────────────────────────────────┐
│  CEILING (Best short position)                      │
│  ═══════════════════════════════════════════        │  ← Price right under Fab Four
│  Price opens HERE                                   │
└─────────────────────────────────────────────────────┘

FOR LONGS:
┌─────────────────────────────────────────────────────┐
│  Price opens HERE                                   │
│  ═══════════════════════════════════════════        │  ← Price right above Fab Four
│  FLOOR (Best long position)                         │
└─────────────────────────────────────────────────────┘

Multi-Timeframe Alignment

Check all timeframes simultaneously:

┌────────┬────────┬────────┬────────┐
│  2min  │  5min  │  15min │  Daily │
│  ────  │  ────  │  ────  │  ────  │
│ Under  │ Under  │ Under  │ Under  │
│  200   │  200   │  200   │  200   │
│ Tight  │ Tight  │ Tight  │ Tight  │
└────────┴────────┴────────┴────────┘
         = ALIGNED = HIGH QUALITY SETUP

Code Implementation

<source lang="python">

  1. File: setup_quality_detection.py:43-48

timeframe_alignment_weight: float = 0.30 # 30% of setup quality score </source>


2.3 Bar-by-Bar vs Big Bar Stops

The Rule

When to Use Stop Method Why
Near MA (hugging) Big Bar stops Eliminates noise
Far from MA (extended) Bar-by-bar stops Protect extended gains

The Warning

Bar-by-bar will knock you out of riches. If there is one stopout that is going to knock you out of the biggest gains of your life, it's going to be bar-by-bar.

Use bar-by-bar ONLY when:

  • Price has moved significantly away from MA
  • "You had better be moving to Pluto"
  • Slant on both 2min and 5min is sharp

Part 3: Stop Loss Methodology

3.1 Stop Placement Hierarchy

Two Stop Options

Type Description When to Use
Event Stop Based on price action event Primary choice
Maximum Stop Dollar-based max loss Fallback when event too far

The Goal

┌─────────────────────────────────────────────────────┐
│  FAB FOUR ZONE (Helping Zone)                       │
├─────────────────────────────────────────────────────┤
│  ↑ STOP SHOULD BE HERE (above/below Fab Four)       │
├─────────────────────────────────────────────────────┤
│  Entry price                                        │
└─────────────────────────────────────────────────────┘

The real goal is to get your stop beyond the Fab Four helping zone.

Code Implementation

<source lang="python">

  1. File: signal_generation_trade_management.py:59-60

min_stop_distance: float = 40.0 # TICKET-13: Increased from 20 default_stop_distance: float = 40.0 # Minimum buffer for price noise </source>


3.2 Stop and Reverse Rules

Three criteria for a valid Stop and Reverse:

Criteria Description
1. Immediate Stop out happens INSTANTLY, not gradually
2. Violent Move that stops you is hard, powerful, shakes earth
3. Decent Position New position is NOT into resistance/support

Invalid Stop and Reverse

❌ Going LONG right INTO the 200 MA
❌ Going LONG right INTO tight Fab Four zone
❌ Going SHORT right INTO strong support

Even if immediate + violent, bad position = no reversal

Code Implementation

<source lang="python">

  1. File: signal_generation_trade_management.py:80-81

bos_structure_lookback: int = 10 # TICKET-11: Extended for BOS stops bos_stop_buffer_points: float = 5.0 # Buffer for structure-based stops </source>


Part 4: Color Change Confirmation

4.1 The Color Change Entry

Entry Trigger

FOR SHORTS:
Red bar closes BELOW green bar's low → ENTER SHORT
Stop: Above the high

FOR LONGS:
Green bar closes ABOVE red bar's high → ENTER LONG
Stop: Below the low

Key Rule: Don't Wait for Bar to Complete

As soon as the red bar crosses below the green, boom boom boom boom boom. You're in.


4.2 Profit Taking Rules

The Two-Bar Rule

Take profits TWO bars after the opposite color, NOT one bar.

SHORT TRADE:
┌─────────────────────────────────────────────────────┐
│  GREEN bar (opposite color)                         │
├─────────────────────────────────────────────────────┤
│  RED bar 1 ← IGNITING bar (DO NOT take profit)      │
├─────────────────────────────────────────────────────┤
│  RED bar 2 ← FOLLOW-THROUGH bar (TAKE PROFIT)       │
└─────────────────────────────────────────────────────┘

Position Management Flow

Step 1: Enter with 2 lots
Step 2: Set stop above high
Step 3: Take profit on 1 lot (first follow-through bar)
Step 4: Move stop to break-even
Step 5: Take profit on remaining lot (second follow-through)
Step 6: Done

The first lot is your REAL trade. The second lot is the cherry on top.

Code Implementation

<source lang="python">

  1. File: signal_generation_trade_management.py:111-118

enable_color_change_filter: bool = False # DISABLED - too restrictive color_change_ma_proximity: float = 20.0 # Points to consider "near" MA require_ma_bounce: bool = False # Don't require strict MA bounce </source>


4.3 The Traffic Jam Concept

When price gaps below everything from prior day:

┌─────────────────────────────────────────────────────┐
│  Yesterday's 200 MA                                 │
│  Yesterday's 20 MA                                  │
│  Yesterday's Close                                  │
│  ═══════════════════════════════════════════        │
│  TRAFFIC JAM ZONE (resistance on any rally)         │
│  ═══════════════════════════════════════════        │
│                                                     │
│  TODAY'S GAP DOWN OPEN                              │
└─────────────────────────────────────────────────────┘

Rule: Any move UP into the traffic jam meets resistance. Short rallies into this zone.


Part 5: Trading Glossary for Engineers

Trading Term System Translation Code Location Why It Matters
Creeper Move Small-bodied bars, consistent direction, low volume market_state_analysis.py:is_creeper_move Institutional accumulation before explosion. PENALTY: -50 points
Railroad Trend Alternating green/red bars touching MA market_state_analysis.py:is_railroad_trend Healthy trend, not overextended. BONUS: +15 points
Two-Day Trend Price consistently above/below MA for 2+ days market_state_analysis.py:has_two_day_trend Confirms trend maturity. Required for A+ grade
Institutional Fight High volume with narrow range market_state_analysis.py:institutional_fight_in_progress Buyers vs sellers battle. MULTIPLIER: 0.7x score
Discount Zone Price below 21 MA (for longs) probability_zone_analysis.py 80% continuation probability
Premium Zone Price above 21 MA (for shorts) probability_zone_analysis.py Entry zone for short trades
Fab Four PDHL, 21 MA, 200 MA, Yesterday's Close signal_generation.py:_calculate_stop_loss() Stop loss placement hierarchy
Color Change Bar closes opposite color after move probability_zone_analysis.py:ColorChangeDetector Confirms reversal/continuation
Break of Structure (BOS) Price closes beyond recent swing H/L market_state_analysis.py:bos_detected Confirms trend continuation/reversal
MA Zone MA is a band, not thin line (21 MA +/- 25pts) signal_generation.py:ma_buffer_points=25 "Fab Four" concept from philosophy
Trend Phase EARLY / MIDDLE / LATE classification market_state_analysis.py:trend_phase MIDDLE phase = optimal entry timing
Crash Bar Bar > 2x average size, violent probability_zone_analysis.py:crash_bar_multiplier Structural break indicator
Traffic Jam Yesterday's price activity zone Conceptual Resistance zone for gaps
Three-Finger Spread Large gap between Price, 21 MA, 200 MA signal_generation.py:three_finger_spread_threshold Market top indicator

Part 6: Component Architecture

6.1 Pipeline Flow

┌─────────────────┐   ┌───────────────────┐   ┌────────────────────┐
│  Data Manager   │ → │  Trend Analysis   │ → │  Market State      │
│  (1M/5M/1H/1D)  │   │  (MA21, MA200)    │   │  (7 Detections)    │
└─────────────────┘   └───────────────────┘   └────────────────────┘
                                                       ↓
┌─────────────────┐   ┌───────────────────┐   ┌────────────────────┐
│  Trade Exec     │ ← │  Signal Gen       │ ← │  Setup Quality     │
│  (P&L, Costs)   │   │  (Entry/Exit)     │   │  (5-Factor Score)  │
└─────────────────┘   └───────────────────┘   └────────────────────┘

6.2 Setup Quality Detection

File: src/components/setup_quality_detection.py

5-Factor Weighted Scoring System

Factor Weight What It Measures
Timeframe Alignment 30% All timeframes agree on direction
Trend Strength 20% Healthy trend without warnings
Entry Quality 15% Entry near MA, clean execution
Key Level Proximity 20% Entry near support/resistance
Risk/Reward 15% Favorable profit potential

Penalty System

Condition Penalty Trading Reason
Creeper Move -50 pts Quiet accumulation = reversal coming
MA Struggle -30 pts Price can't break MA = weak trend
No Two-Day Trend -30 pts Trend not confirmed
Wrong Trend Phase -25 pts Too early or too late in trend
Not Near MA -40 pts Entry too far from edge
Institutional Fight 0.7x Wait for resolution

Grade Thresholds

Grade Score Position Size Auto-Trade?
A+ >= 90 2 lots Yes
A >= 80 1 lot Yes
B >= 70 1 lot No
C >= 60 1 lot No
D >= 50 1 lot No
F < 50 1 lot No

6.3 Market State Analysis

File: src/components/market_state_analysis.py

7 Detection Algorithms

# Algorithm What It Detects Trading Implication
1 Railroad Trend Healthy alternating bars +15 bonus, trend continuation likely
2 Creeper Move Small bars, consistent direction -50 penalty, reversal imminent
3 Volatility Calc ATR-based regime Adjust stop distance
4 Market State TRENDING / SIDEWAYS / VOLATILE Different strategy rules
5 Two-Day Trend Multi-day momentum Required for A+ grade
6 Trend Phase EARLY / MIDDLE / LATE MIDDLE = optimal entry
7 Institutional Behavior Volume + price patterns Fight = wait, Accumulation = prepare

6.4 Signal Generation

File: src/components/signal_generation_trade_management.py

Entry Filters Applied

Filter Config Key Purpose
Hour Filter blocked_hours: [9, 22, 23] Block loss-making hours
MA Direction enable_ma_direction_filter: True LONG only if MA rising
Probability Zone enable_probability_zone_filter: True Entry in favorable zones
Color Change enable_color_change_filter: False Disabled (too restrictive)

Part 7: Branch Changes (service/backtest → rikk_mtf_backtest001)

7.1 Complete Git Diff Summary

Total Changes: 65 files changed across core source, scripts, and data

Modified (M) Source Files

File Type Key Changes
signal_generation_trade_management.py Component TICKET-7,8,10,11,12,13,18,19,20,21,24 + PDF fixes + Grading fix
trade_execution_engine.py Component TICKET-9,13,15,17,20: Trailing stop, breakeven, ATR
market_state_analysis.py Component TICKET-25: 5MIN → 1HOUR data
setup_quality_detection.py Component TICKET-5: Position sizing fix
timeframe_conversion.py Core Date column fix, 1m skip, emoji removal
data_structures.py Core TICKET-15: current_stop_price field
multi_timeframe_analysis.py Component Whitespace cleanup
main.py Entry TICKET-12 config, emoji removal

Added (A) Files

File Purpose
probability_zone_analysis.py NEW: Implements trade_philosophy.pdf (974 lines)
50+ scripts/analyze_*.py Analysis scripts for hypothesis building

7.2 JIRA Ticket Fixes (Complete Details)

TICKET-5: Position Sizing Fix

File: setup_quality_detection.py:544-567

Problem: Previous sizing = 100-200 lots = Rs 5.7 Crore exposure on Rs 1 lakh capital (5700x!)

<source lang="python">

  1. BEFORE (service/backtest):

multipliers = {

   SetupQualityGrade.A_PLUS: 200,  # 200 lots (impossible!)
   SetupQualityGrade.A: 150,
   SetupQualityGrade.B: 100,
   # ...

}

  1. AFTER (rikk_mtf_backtest001):

position_sizes = {

   SetupQualityGrade.A_PLUS: 2,    # 2 lots (Rs 1.14L exposure - realistic)
   SetupQualityGrade.A: 1,         # 1 lot
   SetupQualityGrade.B: 1,
   SetupQualityGrade.C: 1,
   SetupQualityGrade.D: 1,
   SetupQualityGrade.F: 1

} </source>


TICKET-7: R:R Preservation After Slippage

File: signal_generation_trade_management.py:241-285

Problem: Slippage moved entry but stop/target stayed fixed = corrupted R:R ratio

<source lang="python">

  1. BEFORE: Stop and target not adjusted after slippage

actual_execution_price = execution_price + market_slippage # Entry moved

  1. BUT stop_loss_price and take_profit_price stayed at original levels!
  2. RESULT: R:R became inverted (target closer than stop)
  1. AFTER: Shift stop and target with entry to maintain R:R
  2. Example (LONG with +1.5 pts slippage):
  3. Before: entry=5710, stop=5680, target=5740 (30 pts each, 1:1 R:R)
  4. After slippage: entry=5711.5, stop=5680, target=5740
  5. WRONG R:R: stop=31.5 pts, target=28.5 pts (INVERTED!)
  6. FIX: entry=5711.5, stop=5681.5, target=5741.5 (30 pts each, 1:1 R:R)

if signal.direction == Direction.LONG:

   actual_execution_price = execution_price + market_slippage
   # TICKET-7: Shift stop and target UP by slippage to maintain R:R
   adjusted_stop_loss = signal.stop_loss_price + market_slippage
   adjusted_take_profit = signal.take_profit_price + market_slippage

else: # SHORT

   actual_execution_price = execution_price - market_slippage
   # TICKET-7: Shift stop and target DOWN by slippage to maintain R:R
   adjusted_stop_loss = signal.stop_loss_price - market_slippage
   adjusted_take_profit = signal.take_profit_price - market_slippage

</source>


TICKET-8: CTT Rate Fix

File: signal_generation_trade_management.py:48-55

Problem: CTT was 0.05% (5x too high!). Dhan broker calculates Rs 52 on Rs 5.2L = 0.01%

<source lang="python">

  1. BEFORE:

transaction_tax_rate: float = 0.000500 # 0.05% - WRONG!

  1. AFTER:
  2. MCX CTT = 0.01% on SELL side only. Since code charges at entry+exit,
  3. use 0.005% per leg so round-trip = 0.01% total (matches actual CTT)
  4. Dhan verified: CTT Rs 52 on Rs 5,20,000 sell value = 0.01%

transaction_tax_rate: float = 0.000050 # 0.005% per leg × 2 = 0.01% total </source>


TICKET-9: Market Impact Slippage Cap

File: trade_execution_engine.py:40-42, 585-605

Problem: 100 lots × 0.1 = 10 pts slippage (excessive!)

<source lang="python">

  1. BEFORE: No cap on market impact

size_impact = signal.position_size * self.config.market_impact_factor

  1. AFTER: Cap to prevent excessive slippage

max_market_impact_slippage: float = 2.0 # Maximum 2 points

raw_size_impact = signal.position_size * self.config.market_impact_factor size_impact = min(raw_size_impact, self.config.max_market_impact_slippage)

  1. For 1-2 lots (after TICKET-5 fix):
  2. - base: 1.0 pts
  3. - market_impact: min(1×0.1, 2.0) = 0.1 pts (capped at 2.0)
  4. - volatility: 0.5 pts
  5. - total: ~1.6 pts (realistic for MCX crude)

</source>


TICKET-10: Entry Technique Alignment

File: signal_generation_trade_management.py:2012-2140

Problem: Entry technique logic didn't match strategy_engine.py priority order

<source lang="python">

  1. COMPLETE REWRITE of _determine_entry_technique():
  2. BEFORE: Random priority order, creeper before BOS, missing key level checks
  1. AFTER (aligned with strategy_engine.py::_classify_entry_technique_exact()):
  2. PRIORITY 1: Creeper move → NEAR_MA (NOT green_bar/red_bar!)
  3. PRIORITY 2: BOS detected → BOS_ENTRY (only if NOT creeper)
  4. PRIORITY 3: Near key level → DISCOUNT_ZONE / BREAKOUT_PULLBACK
  5. PRIORITY 4: Near MA → MA_BOUNCE
  6. PRIORITY 5: Two-day trend → TWO_GREEN_DAILY / TWO_RED_DAILY
  7. PRIORITY 6: Railroad trend → GREEN_BAR_AFTER_PULLBACK / RED_BAR_AFTER_RALLY
  8. PRIORITY 7: Fallback → NEAR_MA

</source>


TICKET-11: BOS Stop Settings

File: signal_generation_trade_management.py:78-81

Problem: 5-bar lookback + no buffer = stop too close in trending markets = 66.7% stop rate

<source lang="python">

  1. BEFORE:

structure_lookback: int = 5 # Too short for BOS

  1. AFTER:

bos_structure_lookback: int = 10 # Extended lookback for BOS stops bos_stop_buffer_points: float = 5.0 # Buffer below/above structure </source>


TICKET-12: Hour Filter

File: signal_generation_trade_management.py:83-93, 126-137, 571-581

Problem: Certain hours consistently lose money

<source lang="python">

  1. NEW CONFIGURATION:

enable_hour_filter: bool = True blocked_hours: [9, 22, 23] # Block 9-10 AM and after 10 PM

  1. Data-driven analysis showed (from 1439 trades):
  2. Worst hours: 15(-Rs244K), 22(-Rs209K), 09(-Rs199K), 21(-Rs101K), etc.
  3. Profitable hours: 16, 17, 18, 19, 23 (total +Rs341K)
  1. Applied in generate_signal():

if self.config.enable_hour_filter and self.config.blocked_hours:

   current_hour = current_timestamp.hour
   if current_hour in self.config.blocked_hours:
       return None  # No signal during blocked hours

</source>


TICKET-13: Minimum Stop Distance

File: signal_generation_trade_management.py:57-60, 852-870

Problem: 20pt stops hit too frequently due to normal price noise

<source lang="python">

  1. BEFORE:

default_stop_distance: float = 20.000000

  1. AFTER:

min_stop_distance: float = 40.000000 # Minimum stop distance default_stop_distance: float = 40.000000 # Default increased

  1. ENFORCEMENT in generate_signal():
  2. TICKET-13 FIX: ENFORCE MINIMUM STOP DISTANCE (40 POINTS)

stop_distance = max(calculated_stop_distance, self.config.min_stop_distance) </source>


TICKET-15: Trailing Stop Tracking

File: data_structures.py:2982-2984, trade_execution_engine.py:54-70, 295-392

Problem: No way to track current trailing stop position vs original

<source lang="python">

  1. NEW FIELD in Trade dataclass:

current_stop_price: Optional[float] = None # Current trailing stop (moves with price)

  1. NEW METHOD in TradeExecutionEngine:

def _update_trailing_stop(self, trade: Trade, current_high: float, current_low: float):

   """
   TICKET-15/17/20: Update stop based on price movement.
   Two-Phase Stop Management:
   PHASE 1 - Breakeven (TICKET-17): Move stop to entry when profitable
   PHASE 2 - Trailing (TICKET-15/20): Trail stop behind price
   """
   if trade.current_stop_price is None:
       trade.current_stop_price = trade.original_stop_price
   # Calculate trailing distance (ATR-based or fixed)
   if self.config.trailing_stop_method == "ATR_MULTIPLE":
       trailing_distance = self.current_atr * self.config.atr_multiplier
       trailing_distance = max(trailing_distance, 15.0)  # Min 15 pts for Crude
   else:
       trailing_distance = self.config.trailing_stop_distance
   if trade.direction == Direction.LONG:
       current_profit = current_high - trade.entry_price
       if current_profit >= self.config.trailing_stop_activation:
           new_stop = current_high - trailing_distance
           if new_stop > trade.current_stop_price:
               trade.current_stop_price = new_stop  # Only move UP

</source>


TICKET-17: Breakeven Stop

File: trade_execution_engine.py:64-68

Problem: Needed automatic breakeven move when in profit

<source lang="python">

  1. NEW CONFIGURATION:

enable_breakeven_stop: bool = True breakeven_activation: float = 25.0 # Points profit before moving to breakeven breakeven_buffer: float = 2.0 # Points above/below entry for buffer

  1. Tested 10pt activation but cut winners too short (26% WR vs 49%)
  2. 25pt activation is the sweet spot

</source>


TICKET-18: Creeper Move Handling

File: signal_generation_trade_management.py:582-595

Problem: Previous implementation blocked creeper signals entirely (too aggressive)

<source lang="python">

  1. BEFORE: Creeper signals blocked with return None
  1. AFTER (comment explains fix):
  2. CORE BEHAVIOR: Creeper moves get -50 penalty + 0.7x target + uses NEAR_MA
  3. Previous implementation: Blocked entirely with return None (too aggressive)
  4. FIX: Let creeper signals through - penalty applied in setup_quality_detection,
  5. NEAR_MA technique used in _determine_entry_technique()
  6. Let the scoring system decide rather than blocking outright

</source>


TICKET-19: MA Direction Filter + Score Adjustment

File: signal_generation_trade_management.py:95-97, 987-1034, 1955-2010

Problem: Trades against MA21 slope direction had poor performance

<source lang="python">

  1. CONFIGURATION:

enable_ma_direction_filter: bool = True

  1. DIRECTION LOGIC COMPLETE REWRITE (_determine_signal_direction):
  2. BEFORE: Used alignment score threshold (>= 60%)
  3. AFTER: Uses MA21 slope as primary direction source

def _determine_signal_direction(self, timeframe_analysis, market_state, market_data=None):

   """MA21 SLOPE ALIGNMENT DIRECTION LOGIC (trade_philosophy.pdf)"""
   trend_direction = getattr(market_state, 'trend_direction', None)
   if trend_direction == "up":
       return Direction.LONG      # MA21 rising → only LONG
   elif trend_direction == "down":
       return Direction.SHORT     # MA21 declining → only SHORT
   else:
       # Fallback to MTF primary_direction if MA21 is flat/unknown
       return getattr(timeframe_analysis, 'primary_direction', None)
  1. SCORE ADJUSTMENT (lines 987-1034):
  2. +15% bonus if trade direction aligns with MA21 slope
  3. -10% penalty if trade direction against MA21 slope

</source>


TICKET-20: Probability Zone Filter + ATR Trailing

File: signal_generation_trade_management.py:99-109, 628-817, trade_execution_engine.py:57-63, 295-340

Problem: Needed trade_philosophy.pdf concepts in code

<source lang="python">

  1. NEW CONFIGURATION (Probability Zones):

enable_probability_zone_filter: bool = True probability_zone_swing_lookback: int = 20 probability_zone_min_range: float = 20.0 three_finger_spread_threshold: float = 0.02 crash_bar_multiplier: float = 2.0 sideways_mean_reversion: bool = True

  1. NEW CONFIGURATION (ATR Trailing):

trailing_stop_method: str = "ATR_MULTIPLE" # or "FIXED_POINTS" atr_period: int = 14 atr_multiplier: float = 2.0 # 2x ATR = trailing distance

  1. NEW ATR CALCULATION in trade_execution_engine.py:295-340

def _calculate_atr(self, five_min_data: Dict) -> None:

   """Calculate Average True Range for dynamic trailing stop."""
   # TrueRange = max(high-low, abs(high-prev_close), abs(low-prev_close))
   # ATR = SMA(TrueRange, period)
   true_ranges = []
   for i in range(1, len(high_vals)):
       tr = max(
           high_vals[i] - low_vals[i],           # Current high - low
           abs(high_vals[i] - close_vals[i-1]),  # High - previous close
           abs(low_vals[i] - close_vals[i-1])    # Low - previous close
       )
       true_ranges.append(tr)
   self.current_atr = sum(true_ranges) / len(true_ranges)

</source>


TICKET-21: Color Change Filter (DISABLED)

File: signal_generation_trade_management.py:111-118

Problem: color_change.pdf patterns too restrictive for automation

<source lang="python">

  1. CONFIGURATION (disabled):

enable_color_change_filter: bool = False # DISABLED - too restrictive color_change_ma_proximity: float = 20.0 # Points to consider "near" MA require_ma_bounce: bool = False # Too strict color_change_require_in_zones: bool = True

  1. NOTE: ColorChangeDetector class still exists for future use
  2. Implements liquidity sweep patterns:
  3. - LONG: Green bar sweeps BELOW red bar low + bounce from 21 MA
  4. - SHORT: Red bar sweeps ABOVE green bar high + rejection from 21 MA

</source>


TICKET-24: Creeper Move Entry Technique Fix

File: signal_generation_trade_management.py:2037-2050

Problem: strategy_engine.py bug - uses wrong entry technique for creeper moves

<source lang="python">

  1. STRATEGY ENGINE BUG FOUND:
  2. backtesting_standalone/src/strategy_engine.py lines 3338-3380
  3. checks bos_detected FIRST but doesn't consider is_creeper_move.
  4. This causes BOS entries in creeper moves (inappropriate).
  1. FIX: Check creeper FIRST before BOS

if is_creeper:

   # Creeper gets -50 penalty + 0.7x target from setup_quality_detection
   # But uses NEAR_MA as technique (NOT green_bar/red_bar!)
   return EntryTechnique.NEAR_MA  # Strategy engine fallback

</source>


TICKET-25: Market State 5MIN → 1HOUR

File: market_state_analysis.py:191-360

Problem: Creeper threshold 0.5% calibrated for 1H bars (~0.8-1.2% range), but code used 5MIN (~0.16% range) = 98.9% false positives!

<source lang="python">

  1. BEFORE:

required_tf = TimeframeValue.FIVE_MIN

  1. AFTER:

def validate_input(self, input_data: Dict, context: ComponentContext):

   """
   TICKET-25 FIX: Market state analysis uses 1-HOUR data (not 5MIN)
   to match strategy_engine.py behavior for creeper/railroad detection.
   """
   primary_tf = TimeframeValue.ONE_HOUR
   fallback_tf = TimeframeValue.FIVE_MIN
   if primary_tf in input_data and input_data[primary_tf] is not None:
       required_tf = primary_tf
   elif fallback_tf in input_data and input_data[fallback_tf] is not None:
       required_tf = fallback_tf
       # Warning: 5MIN fallback may cause inaccurate creeper detection

def _get_primary_timeframe(self, input_data: Dict) -> TimeframeValue:

   """
   TICKET-25 FIX: Use ONE_HOUR for market state analysis.
   The 0.5% creeper threshold is calibrated for 1-HOUR bars (~0.8-1.2% typical range),
   not 5-MIN bars (~0.16% typical range). Using 5MIN caused 98.9% false positives.
   """
   primary_tf = TimeframeValue.ONE_HOUR  # Was FIVE_MIN

</source>


PDF-FIX: MA Buffer Points

File: signal_generation_trade_management.py:67-68

Source: Fab Four concept - "MA is a zone, not a thin line"

<source lang="python">

  1. BEFORE:

ma_buffer_points: float = 5.000000 # Too tight!

  1. AFTER:
  2. PDF-FIX: MA is a "zone, not a thin line" (Fab Four) - use wider buffer

ma_buffer_points: float = 25.000000 # 21 MA zone width </source>


PDF-FIX: Take Profit Calculation Rewrite

File: signal_generation_trade_management.py:1620-1677

Problem: Old method used strategy.entry_exit_settings with FIXED_POINTS, ATR_MULTIPLE, etc. PDF philosophy uses 50% of prior move.

<source lang="python">

  1. BEFORE: Used strategy config with multiple methods

def _calculate_take_profit(self, strategy, entry_price, stop_loss_price, direction):

   profit_target_method = strategy.entry_exit_settings.profit_target_method
   if profit_target_method == ProfitTargetMethod.FIXED_POINTS:
       profit_points = strategy.entry_exit_settings.profit_target_points or 25
       return entry_price + profit_points  # etc.
   elif profit_target_method == ProfitTargetMethod.ATR_MULTIPLE:
       # ... ATR logic
  1. AFTER: PDF-based 50% mean reversion target

def _calculate_take_profit(self, strategy, entry_price, stop_loss_price, direction, market_data=None):

   """PDF-FIX: Target = 50% of prior move (trade_philosophy.pdf)"""
   if market_data:
       ma21_series = tf_data.get("ma21")
       if ma21_series is not None:
           ma_21 = float(ma21_series.iloc[-1])
           # Calculate 50% move toward MA
           distance_to_ma = abs(entry_price - ma_21)
           target_distance = distance_to_ma * 0.5
           # But ensure minimum target based on risk
           risk_distance = abs(entry_price - stop_loss_price)
           min_target = risk_distance * 1.5  # At least 1.5:1 R:R
           target_distance = max(target_distance, min_target)
           return entry_price + target_distance  # (or minus for SHORT)
   # Fallback to 2:1 R:R if no MA data
   risk_distance = abs(entry_price - stop_loss_price)
   return entry_price + (risk_distance * 2)

</source>


PDF-FIX: CRASH SHORT Detection (Direction Override)

File: signal_generation_trade_management.py:700-750

Logic: In sideways market at top zone, big RED bar breaking below 21 MA overrides LONG direction to SHORT

<source lang="python">

  1. NEW CODE: Crash SHORT detection within probability zone filter
  2. Per PDF: In top third, big RED bar breaking 21 MA = SHORT signal

is_red_bar = current_close < current_open is_big_bar = current_range > avg_range * 1.2 # 1.2x average = significant bar breaks_below_ma = current_close < (ma_21 - 25.0) # Below MA zone was_above_ma = current_open > (ma_21 - 25.0) is_top_zone = zone_result.zone in [ProbabilityZone.TOP_THIRD, ProbabilityZone.TOP_HALF] is_sideways = market_state_str in ["creeper", "creeper_move", "sideways", "consolidation"]

  1. CRASH SHORT DETECTION: Override LONG to SHORT in sideways markets

if is_sideways and is_top_zone and is_big_bar and is_red_bar and breaks_below_ma and was_above_ma:

   self.logger.debug(f"CRASH SHORT DETECTED: Overriding {direction} to SHORT")
   direction = Direction.SHORT
   is_crash_short = True  # Flag to skip color change filter

</source>


PDF-FIX: Stop Loss Calculation (NEAR_MA technique)

File: signal_generation_trade_management.py:1490-1530

Problem: Old code placed stop relative to MA value. New code uses structure low/high.

<source lang="python">

  1. BEFORE: Stop below/above MA value

if entry_technique == EntryTechnique.NEAR_MA_LONG:

   if ma21_values is not None:
       ma_value = ma21_values[-1]
       buffer_points = self.config.ma_buffer_points
       stop_loss = ma_value - buffer_points  # Below MA
  1. AFTER: Stop below structure low (more robust)

if entry_technique == EntryTechnique.NEAR_MA_LONG:

   # PDF-FIX: Stop should be below recent structure low, not just below MA
   # When price is already below MA (LONG per new direction logic),
   # stop below MA would be above entry = wrong!
   lookback = self.config.structure_lookback  # 5 bars
   if len(low_values) >= lookback:
       structure_low = min(low_values[-lookback:])
       stop_loss = structure_low - self.config.ma_buffer_points
       # Ensure stop is below entry
       if stop_loss >= entry_price:
           stop_loss = entry_price - self.config.default_stop_distance

</source>


GRADING FIX: Score-to-Grade Recalculation

File: signal_generation_trade_management.py:1054, 1132-1170

Problem: Grade assigned from capped original score instead of adjusted score

<source lang="python">

  1. BEFORE:

setup_quality=setup_quality.grade, # Grade from CAPPED original score (79) setup_score=setup_quality.score, # Original score (79)

  1. Problem: Score=79 → Grade=A, but if adjustment makes it 89, should be A+!
  1. AFTER:

setup_quality=self._calculate_grade_from_score(adjusted_score), # RECALCULATED setup_score=adjusted_score, # MA-adjusted score

  1. NEW METHOD ADDED:

def _calculate_grade_from_score(self, score: float) -> SetupQualityGrade:

   """GRADING FIX: Calculate grade from FINAL adjusted score."""
   if score >= 90: return SetupQualityGrade.A_PLUS
   elif score >= 80: return SetupQualityGrade.A
   elif score >= 70: return SetupQualityGrade.B
   elif score >= 60: return SetupQualityGrade.C
   elif score >= 50: return SetupQualityGrade.D
   else: return SetupQualityGrade.F

</source>


7.3 New File: probability_zone_analysis.py (974 lines)

This file implements concepts from trade_philosophy.pdf:

Enums Defined

<source lang="python"> class ProbabilityZone(Enum):

   TOP_THIRD = "top_third"           # 80% continuation probability
   TOP_HALF = "top_half"             # 65% continuation probability
   BOTTOM_HALF = "bottom_half"       # 35% continuation probability
   BOTTOM_THIRD = "bottom_third"     # 15% continuation (85% reversal)

class MarketStructure(Enum):

   UPTREND = "uptrend"               # Price > 21 MA > 200 MA
   DOWNTREND = "downtrend"           # Price < 21 MA < 200 MA
   SIDEWAYS = "sideways"             # No clear structure
   THREE_FINGER_SPREAD_BULL = "..."  # Large spread (bearish signal)
   THREE_FINGER_SPREAD_BEAR = "..."  # Large spread (bullish signal)

class PullbackType(Enum):

   HEALTHY_PULLBACK = "healthy_pullback"  # 45-degree drift, holds above halfway
   COLLAPSE = "collapse"                   # Vertical drop, breaks deeply
   NO_PULLBACK = "no_pullback"            # Price at or near highs
   BOUNCE = "bounce"                       # Bounce after crash (short opportunity)

class ColorChangeType(Enum):

   BULLISH_REVERSAL = "bullish_reversal"  # Green bar takes out red bar high
   BEARISH_REVERSAL = "bearish_reversal"  # Red bar takes out green bar low
   NO_PATTERN = "no_pattern"

</source>

Key Classes

  • ProbabilityZoneResult - Analysis result with zone, probabilities, MA structure
  • ColorChangeResult - Pattern detection result
  • ProbabilityZoneConfig - Configuration with thresholds
  • ProbabilityZoneAnalyzer - Main analyzer class
  • ColorChangeDetector - Detects liquidity sweep patterns

Configuration Defaults

<source lang="python"> @dataclass class ProbabilityZoneConfig:

   top_third_probability: float = 0.80    # 80% continuation
   top_half_probability: float = 0.65     # 65% continuation
   bottom_half_probability: float = 0.35  # 35% continuation
   bottom_third_probability: float = 0.15 # 15% continuation
   swing_lookback_bars: int = 20          # Bars for swing H/L
   crash_bar_multiplier: float = 2.0      # Bar > 2x avg = crash
   three_finger_min_spread_pct: float = 0.02  # 2% spread threshold

</source>


7.4 timeframe_conversion.py Changes

File: src/core/timeframe_conversion.py

Changes

  1. Emoji removal - All emoji characters replaced with [OK], [FAIL], [CONV], etc.
  2. Date column fix - Handle 'date' as alias for 'timestamp'
  3. 1m skip - Don't overwrite source file when saving
  4. Mixed timestamp format - Use format='mixed' for pandas parsing

<source lang="python">

  1. Date column alias:

if 'date' in source_df.columns and 'timestamp' not in source_df.columns:

   source_df = source_df.rename(columns={'date': 'timestamp'})
   logger.info("[FIX] Renamed 'date' column to 'timestamp'")
  1. Skip 1m overwrite:

if timeframe == '1m':

   logger.info(f"[SKIP] 1m: Source file preserved (not overwritten)")
   continue
  1. Mixed timestamp parsing:

pd.to_datetime(df['timestamp'], format='mixed') </source>


7.5 main.py Changes

File: src/main.py

Changes

  1. Hour filter configuration - TICKET-12 support
  2. Emoji removal - Console output cleanup

<source lang="python">

  1. TICKET-12: Hour Filter configuration:

enable_hour_filter=strategy_config.get('enable_hour_filter', False), blocked_hours=strategy_config.get('blocked_hours', [])

print(f" TICKET-12 Hour Filter: Enabled={signal_generator_config.enable_hour_filter}, "

     f"Blocked Hours={signal_generator_config.blocked_hours}")

</source>


7.6 Complete File Tree

services/backtest/src/
├── components/
│   ├── market_state_analysis.py      # TICKET-25: 5MIN → 1HOUR
│   ├── multi_timeframe_analysis.py   # Whitespace cleanup
│   ├── probability_zone_analysis.py  # NEW: trade_philosophy.pdf (974 lines)
│   ├── setup_quality_detection.py    # TICKET-5: position sizing
│   ├── signal_generation_trade_management.py  # TICKET-7,8,10,11,12,13,18,19,20,21,24 + GRADING FIX
│   └── trade_execution_engine.py     # TICKET-9,13,15,17,20: trailing/breakeven/ATR
├── core/
│   ├── data_structures.py            # TICKET-15: current_stop_price field
│   └── timeframe_conversion.py       # Date fix, 1m skip, emoji removal
└── main.py                           # TICKET-12 config, emoji removal

services/backtest/scripts/           # 50+ NEW analysis scripts
├── analyze_alignment_pnl.py
├── analyze_alignment_pnl_v2.py
├── analyze_aplus.py
├── analyze_by_hour.py
├── analyze_combined_filters.py
├── analyze_crash_short_potential.py
├── analyze_hour_filter.py
├── analyze_hourly_pnl.py
├── analyze_long_short_detail.py
├── analyze_longs.py
├── analyze_ma_alignment.py
├── analyze_ma_slope_filter.py
├── analyze_morning_times.py
├── analyze_pdf_results.py
├── analyze_quick_exits.py
├── analyze_red_bar_rally.py
├── analyze_shorts.py
├── analyze_stop_exits.py
├── analyze_stop_loss_detail.py
├── analyze_test_summary.py
├── analyze_trade_bias.py
├── analyze_trading_hours_filter.py
├── analyze_trend_direction_at_entry.py
├── aplus_vs_a_analysis.py
├── check_all_data.py
├── check_costs.py
├── check_data_range.py
├── check_price_trend.py
├── comprehensive_analysis.py
├── comprehensive_backtest_analysis.py
├── comprehensive_summary.py
├── cost_impact_analysis.py
├── detailed_monthly.py
├── diagnose_color_change.py
├── diagnose_direction_bias.py
├── framework_comparison_analysis.py
├── generate_test_summary.py
├── grade_and_equity.py
├── monthly_breakdown.py
├── no_morning_analysis.py
├── path_to_profitability.py
├── philosophy_v1_blend_analysis.py
├── root_cause_summary.py
├── short_market_state_alignment.py
├── short_technique_analysis.py
├── simulate_target_rr.py
├── simulate_target_rr_v2.py
├── stop_out_deep_analysis.py
├── strategy_engine_gap_analysis.py
├── test_summary.py
└── v1_optimization_impact_analysis.py

Part 8: Strategy Configuration

8.1 76D Parameter Vector

The strategy uses regime-aware configuration with 76 parameters:

  • 44 Global Parameters - Constant across all market regimes
  • 32 Regime Parameters - 8 parameters × 4 market regimes

File: src/config/strategy_config.py

Key Parameters

Parameter Default Description
primary_ma_period 21 Main trend MA
secondary_ma_period 200 Long-term trend MA
default_stop_distance 40 pts Minimum stop distance
default_risk_reward 2.0 Target R:R ratio
ma_buffer_points 25 pts MA zone width
creeper_move_penalty -50 Score reduction
railroad_trend_bonus +15 Score increase

Part 9: Decision Trees

9.1 Should I Trade This Setup?

START: Signal Generated
   │
   ▼
[Is hour blocked (9, 22, 23)?]
   │ Yes → SKIP (loss-making hours)
   │ No ↓
   ▼
[Is MA21 direction aligned with trade?]
   │ LONG + MA rising? → Continue
   │ SHORT + MA falling? → Continue
   │ No alignment → SKIP
   │
   ▼
[Is price in probability zone?]
   │ LONG + Bottom Third? → Continue (80% odds)
   │ SHORT + Top Third? → Continue (80% odds)
   │ Wrong zone → SKIP
   │
   ▼
[Calculate Setup Quality Score]
   │
   ├─ Apply 5-factor scoring (TF 30%, Trend 20%, Entry 15%, KeyLevel 20%, R:R 15%)
   ├─ Apply penalties (creeper -50, MA struggle -30, etc.)
   ├─ Apply institutional fight multiplier (0.7x)
   ├─ Apply MA direction adjustment (+15% aligned, -10% against)
   │
   ▼
[Recalculate Grade from ADJUSTED score]
   │
   ├─ A+ or A → Auto-trade eligible (2 lots for A+, 1 lot for A)
   ├─ B to D → Manual review (1 lot)
   ├─ F → Skip or minimal size
   │
   ▼
[Execute Trade with Position Size]

9.2 Where to Place Stop?

START: Trade Direction Determined
   │
   ▼
[Is Fab Four zone tight and close?]
   │ Yes → Place stop BEYOND Fab Four zone
   │ No ↓
   ▼
[Can I afford stop beyond Fab Four?]
   │ Yes → Use EVENT stop (beyond Fab Four)
   │ No → Use MAXIMUM loss stop ($6000 max)
   │
   ▼
[ENFORCE minimum 40pt stop (TICKET-13)]
   │
   ▼
[Once trade moves in favor:]
   │
   ├─ 25 pts profit → Move stop to breakeven (TICKET-17)
   ├─ 20+ pts profit → Start trailing (TICKET-15/20)
   ├─ Use ATR-based trail distance (2x ATR, min 15 pts)
   │
   ▼
[Stop Placement Complete]

Part 10: Code Review Guidelines

10.1 What Reviewers Should Check

  • Code correctness (syntax, bugs)
  • Integration (doesn't break other components)
  • Test coverage
  • Precision (6-decimal places per spec)
  • Performance (no excessive logging)

10.2 What Reviewers Should NOT Question

  • The penalty values themselves (-50, -30, etc.)
  • Why 21 MA and not 20 MA
  • Why specific thresholds (these are trading decisions)
  • Why certain hours are blocked

10.3 Trading Authority Principle

Rikk has final authority on:

  • Entry/exit conditions
  • Threshold values
  • Setup definitions
  • What constitutes a valid signal
  • Penalty/bonus amounts

Engineers have authority on:

  • Code quality and structure
  • Performance optimization
  • Error handling
  • System integration
  • Test coverage

Part 11: Quick Reference Cards

Card 1: Probability Zones

TOP THIRD    = 80% continuation (SHORT zone)
TOP HALF     = 65% continuation
BOTTOM HALF  = 35% continuation
BOTTOM THIRD = 15% continuation (LONG zone with 85% reversal odds)

Card 2: Setup Quality Formula

Score = (TF_align × 0.30) + (Trend × 0.20) + (Entry × 0.15) + (KeyLevel × 0.20) + (R:R × 0.15)

Then apply:
- Creeper detected? → Score - 50
- MA struggle? → Score - 30
- No two-day trend? → Score - 30
- Wrong phase? → Score - 25
- Institutional fight? → Score × 0.7
- MA direction aligned? → Score + 15%
- MA direction against? → Score - 10%

Finally: Recalculate grade from ADJUSTED score (not original!)

Card 3: Profit Taking

1. Enter with 2 lots
2. Set stop above high (short) / below low (long)
3. Wait for follow-through bar (2nd bar after opposite color)
4. Take profit on 1 lot
5. Move stop to break-even
6. Wait for next follow-through bar
7. Take profit on remaining lot
8. Done

Card 4: All Code Changes Summary

Change One-Line Summary
TICKET-5 Position sizing: 200 lots → 2/1 lots (realistic for Rs 1L capital)
TICKET-7 R:R preservation: shift stop/target with slippage
TICKET-8 CTT rate: 0.05% → 0.005% per leg (5x fix)
TICKET-9 Market impact: cap slippage at 2 pts max
TICKET-10 Entry technique: align with strategy_engine.py priority order
TICKET-11 BOS stops: 5 → 10 bar lookback + 5pt buffer
TICKET-12 Hour filter: block hours 9, 22, 23 (loss-making)
TICKET-13 Min stop: 20 → 40 pts (noise protection)
TICKET-15 Trailing stop: add current_stop_price tracking
TICKET-17 Breakeven: move stop to entry at 25pt profit
TICKET-18 Creeper handling: let through (don't block), use penalty
TICKET-19 MA direction: use slope as primary direction source + score adjustment
TICKET-20 Probability zones + ATR trailing (trade_philosophy.pdf)
TICKET-21 Color change: disabled (too restrictive)
TICKET-24 Creeper entry: use NEAR_MA technique (not green/red bar)
TICKET-25 Market state: 5MIN → 1HOUR for creeper detection
GRADING FIX Recalculate grade from adjusted score (not capped original)
PDF-FIX: MA Buffer 5 → 25 pts (MA is zone, not line)
PDF-FIX: Take Profit Rewrite to 50% of distance-to-MA (mean reversion)
PDF-FIX: Crash SHORT Direction override: sideways + top zone + big red bar → SHORT
PDF-FIX: Stop Loss NEAR_MA stop uses structure low (not MA value)
NEW: __post_init__ Initialize blocked_hours list after dataclass creation
NEW: _calculate_grade_from_score New method to recalculate grade from adjusted score
NEW: probability_zone_analysis.py 974-line new file implementing trade_philosophy.pdf
NEW: 50+ analysis scripts Scripts for hypothesis building and analysis

Last Updated: 2026-01-05 | Branch: rikk_mtf_backtest001 | Validated: 19-month backtest