Skip to content

fix(strategy): cap HTF adjustment when short-term indicators show consensus#347

Merged
TheodorStorm merged 4 commits intodevelopfrom
fix/issue-342
Jan 22, 2026
Merged

fix(strategy): cap HTF adjustment when short-term indicators show consensus#347
TheodorStorm merged 4 commits intodevelopfrom
fix/issue-342

Conversation

@claude
Copy link
Contributor

@claude claude bot commented Jan 10, 2026

Summary

  • Caps HTF bias adjustment to ±10 when RSI and Bollinger both unanimously signal overbought/oversold
  • Prevents HTF from completely overriding timely exit/entry signals during short-term indicator consensus
  • Applied in all HTF adjustment code paths (normal, extreme fear override)

Problem

Trade #239 example:

  • RSI: -20 (overbought at 65.1)
  • Bollinger: -30 (27% above upper band)
  • Both indicators unanimously signaled overbought
  • HTF applied +30 adjustment, converting -45 to -7
  • Result: Missed sell opportunity

Solution

When both RSI and Bollinger show consensus:

  • Bearish/overbought: RSI <= -15 AND BB <= -20
  • Bullish/oversold: RSI >= 15 AND BB >= 20

Cap the HTF adjustment to ±10 instead of ±30. With the example above, score would be ~-25 (still a sell signal).

Trade-offs

  • Pro: Allows timely exits when short-term indicators unanimously agree
  • Pro: Surgical fix that preserves HTF benefit in normal cases
  • Con: More complex logic to maintain

Test plan

  • Run full test suite: python3 -m pytest tests/ --ignore=tests/test_coinbase_integration_live.py -v
  • Verify 149 signal scorer tests pass
  • Manual verification: Monitor paper trading for capping behavior

Closes #342

🤖 Generated with Claude Code

…sensus

When RSI and Bollinger both signal overbought/oversold unanimously,
cap the HTF bias adjustment to ±10 instead of ±30. This prevents
HTF from completely overriding timely exit/entry signals when
short-term indicators agree.

Consensus detection thresholds:
- Bearish/overbought: RSI <= -15 AND BB <= -20
- Bullish/oversold: RSI >= 15 AND BB >= 20

Example from Trade #239:
- RSI: -20 (overbought), BB: -30 (27% above upper band)
- Both unanimously signaled overbought
- HTF applied +30, converting -45 to -7
- With cap of ±10, score would be ~-25 (still a sell signal)

Closes #342

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link
Contributor Author

claude bot commented Jan 10, 2026

PR Review: fix(strategy): cap HTF adjustment when short-term indicators show consensus

Summary

This PR addresses issue #342 where the Higher Timeframe (HTF) bias was overriding short-term indicator consensus, causing missed trading opportunities. The fix caps HTF adjustments to ±10 when both RSI and Bollinger indicators unanimously signal overbought/oversold conditions.


🟢 Low Priority Issues

1. Code Duplication - Three Nearly Identical Capping Blocks

The HTF adjustment capping logic is duplicated in three places:

  • Lines 1114-1124 (extreme fear bearish daily buy)
  • Lines 1143-1153 (extreme fear bullish daily sell)
  • Lines 1178-1188 (normal HTF adjustment path)

Observation: The two blocks inside the extreme fear override branches cap the adjustment but then extreme_fear_override_applied = True is set immediately after, which means the third capping block at lines 1178-1188 will never run for these cases (since it's after the extreme fear branches). This is correct behavior, but the duplication could be confusing.

Suggestion: Consider extracting this into a helper function:

def _cap_htf_adjustment_for_consensus(
    htf_adjustment: int,
    short_term_consensus: bool,
    rsi_score: int,
    bb_score: int,
    cap: int = 10
) -> int:
    """Cap HTF adjustment when short-term indicators show consensus."""
    if short_term_consensus and abs(htf_adjustment) > cap:
        logger.info(
            "htf_adjustment_capped",
            reason="short_term_consensus",
            original=htf_adjustment,
            capped=max(-cap, min(cap, htf_adjustment)),
            rsi_score=rsi_score,
            bb_score=bb_score,
        )
        return max(-cap, min(cap, htf_adjustment))
    return htf_adjustment

Impact: Low - the code is correct, this is a maintainability improvement.


2. Missing Test Coverage for New Behavior

The PR adds significant new logic but there are no new tests for the short_term_consensus capping behavior. A grep for short_term_consensus or htf_adjustment_capped in tests returns no results.

Required Tests:

  1. Test that HTF adjustment is capped to ±10 when RSI <= -15 AND BB <= -20 (bearish consensus)
  2. Test that HTF adjustment is capped to ±10 when RSI >= 15 AND BB >= 20 (bullish consensus)
  3. Test that HTF adjustment is NOT capped when only one indicator meets threshold
  4. Test that capping works correctly in extreme_fear override paths
  5. Test edge cases: RSI = -15, BB = -20 (exactly at threshold)

Impact: Low for merge, but tests should be added before this behavior is relied upon in production.


3. Magic Number: 10 for Cap Value

The cap value of 10 is hardcoded in multiple places. Consider making this a configurable constant:

# At class level or module level
SHORT_TERM_CONSENSUS_HTF_CAP = 10

Impact: Low - this is a minor maintainability improvement.


✅ Positive Observations

  1. Clear PR description: The problem, solution, and trade-offs are well documented.
  2. Surgical fix: The change is focused and minimal, preserving existing HTF behavior in normal cases.
  3. Good logging: The htf_adjustment_capped log entries provide excellent observability for monitoring this behavior.
  4. Sensible thresholds: RSI ±15 (60% of max) and BB ±20 (100% of max) are reasonable thresholds for detecting indicator consensus.
  5. Correct logic flow: The extreme fear override paths correctly handle capping before applying the adjustment.

Verdict

Approve with suggestions. The logic is correct and addresses the issue well. The code quality issues are minor (duplication, magic number, missing tests) and can be addressed in follow-up work.

Recommended action:

  • ✅ Merge is acceptable
  • 📝 Create a follow-up issue for adding test coverage
  • 📝 Consider refactoring the duplicate capping logic in a future PR

Review by claude[bot]

- Extract HTF consensus capping into reusable helper function
  `_cap_htf_adjustment_for_consensus()` to reduce code duplication
- Add `SHORT_TERM_CONSENSUS_HTF_CAP` constant (value: 10) for the
  cap value previously hardcoded in multiple places
- Add comprehensive test suite for short-term consensus HTF capping:
  - Unit tests for helper function covering positive/negative caps,
    edge cases at boundaries, and custom cap values
  - Integration tests for bearish/bullish consensus detection
  - Test for extreme fear path with consensus

All review issues addressed:
- Issue 1 (code duplication): Extracted to helper function
- Issue 2 (missing tests): Added 13 new tests
- Issue 3 (magic number): Extracted to named constant

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

Review feedback addressed. Please re-review.

Workflow run

@claude
Copy link
Contributor Author

claude bot commented Jan 10, 2026

🔍 PR Review: fix(strategy): cap HTF adjustment when short-term indicators show consensus

Summary

This PR addresses issue #342 by capping the HTF (Higher Timeframe) bias adjustment when short-term indicators (RSI and Bollinger) show unanimous consensus on overbought/oversold conditions. The implementation is well-structured and follows good software engineering practices.


✅ Code Quality & Best Practices

Strengths:

  1. Well-structured helper function - The _cap_htf_adjustment_for_consensus() function is cleanly extracted with proper docstring, type hints, and clear parameter documentation
  2. Named constant - SHORT_TERM_CONSENSUS_HTF_CAP = 10 avoids magic numbers and makes the value configurable
  3. Consistent application - The capping logic is applied in all three HTF adjustment paths (normal, extreme fear bullish, extreme fear bearish)
  4. Good logging - The helper function logs when capping occurs with relevant context (original value, capped value, indicator scores)
  5. Returns tuple - Returning (capped_value, was_capped) enables callers to know if capping occurred for future debugging/analysis

Suggestions:

  • 🟢 Low: Consider adding the SHORT_TERM_CONSENSUS_HTF_CAP to config/settings.py if you anticipate needing to tune this value without code changes

🧪 Test Coverage

Excellent test coverage added (240 new lines):

  • ✅ Unit tests for the helper function covering:
    • Positive/negative adjustment capping
    • No capping when consensus is False
    • No capping when within limit
    • Boundary cases (exactly at cap, just over cap)
    • Custom cap value parameter
  • ✅ Integration tests for consensus detection in calculate_score()
  • ✅ Edge case test for extreme fear path
  • ✅ Test for single indicator not triggering consensus

Minor observation:

  • The integration tests (test_bearish_consensus_detection, test_bullish_consensus_detection) create synthetic data and check assertions conditionally (if result.score < 0). This is reasonable given the complexity of creating exact indicator scores, but the tests might silently pass without actually exercising the assertion. Consider adding explicit assertions that the test data produces the expected conditions.

🔒 Security Concerns

No security issues identified. This PR modifies trading signal calculation logic but:

  • Does not introduce any new external inputs
  • Does not modify any exchange API interactions
  • Does not affect order execution logic directly
  • Only adjusts internal score calculations

⚡ Performance Considerations

No performance concerns. The changes:

  • Add a simple comparison (abs(htf_adjustment) > cap)
  • Use basic math operations (max, min)
  • Called once per calculate_score() execution (3 potential call sites, but only one executes per signal)

🏗️ Architecture Review

Consensus detection logic is sound:

short_term_consensus = (
    (rsi_score <= -15 and bb_score <= -20) or  # Both bearish/overbought
    (rsi_score >= 15 and bb_score >= 20)       # Both bullish/oversold
)

The thresholds are reasonable:

  • RSI ±15 represents 60% of max score (25)
  • BB ±20 represents 100% of max score (20)

This ensures only strong consensus triggers the cap.

Potential edge case to consider:

  • 🟢 Low: When extreme_fear_override_applied = True, the cap function is called twice (once in the extreme fear block, once after). The second call has no effect since the adjustment was already handled, but it's redundant code execution. Consider restructuring to avoid this, or at least document why it's intentional.

📋 Checklist

Aspect Status Notes
Conventional commit format fix(strategy): prefix used correctly
Tests added Comprehensive test coverage
No magic numbers Constant extracted
Documentation Good docstrings and inline comments
PR description Clear problem statement and solution
Breaking changes ✅ None Backward compatible

🎯 Verdict

Overall: Approve with minor suggestions 👍

This is a well-implemented fix for a real trading issue (Trade #239 example). The code is clean, well-tested, and follows the repository's patterns. The refactoring commit addressed previous review feedback appropriately.

Priority of suggestions:

  • All suggestions are 🟢 Low priority and can be addressed in future PRs if desired

No blocking issues identified.

- Avoid redundant cap function call in extreme_fear path by wrapping
  the second _cap_htf_adjustment_for_consensus call in a conditional
- Improve integration tests for consensus detection by using mocked
  indicator functions instead of synthetic price data that may not
  produce the expected indicator scores
- Add explicit assertions to catch when test data doesn't produce
  expected conditions instead of silently passing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

Review feedback addressed. Please re-review.

Workflow run

@claude
Copy link
Contributor Author

claude bot commented Jan 10, 2026

PR Review: fix(strategy): cap HTF adjustment when short-term indicators show consensus

Summary

This PR addresses issue #342 where HTF (Higher Timeframe) bias adjustments were overriding short-term indicator consensus, causing missed trading opportunities. The fix caps HTF adjustments to ±10 when RSI and Bollinger bands both unanimously signal overbought/oversold conditions.


✅ What's Good

1. Well-Designed Solution

  • The approach is surgical and targeted - it only caps HTF adjustments when there's clear short-term consensus
  • Preserves the benefit of HTF filtering in normal cases while allowing timely exits/entries during strong signals
  • The consensus thresholds (RSI ±15, BB ±20) are sensible - requiring ~60% of RSI max and 100% of BB max

2. Clean Implementation

  • The helper function _cap_htf_adjustment_for_consensus() is well-documented and reusable
  • Good separation of concerns - the capping logic is isolated in its own function
  • Proper logging when capping occurs for debugging/monitoring
  • The function returns both the capped value AND a boolean indicating if capping occurred

3. Comprehensive Test Coverage

  • 13 new tests covering the helper function edge cases
  • Tests for both bearish and bullish consensus detection
  • Tests for boundary conditions (at cap, just over cap)
  • Integration tests with the extreme fear path
  • The tests use mocking appropriately to isolate the consensus logic

4. Documentation

  • Excellent PR description explaining the problem, solution, and trade-offs
  • Good inline comments explaining the rationale

🟡 Suggestions (Non-blocking)

1. Consider Adding a Test for Zero HTF Adjustment
The helper function handles the case where htf_adjustment=0 correctly (returns 0, not capped), but there's no explicit test for this edge case. Consider adding:

def test_helper_zero_adjustment(self):
    """Test zero HTF adjustment is not modified."""
    result, was_capped = _cap_htf_adjustment_for_consensus(
        htf_adjustment=0,
        short_term_consensus=True,
        rsi_score=20,
        bb_score=20,
    )
    assert result == 0
    assert was_capped is False

2. Consider Logging When Consensus is Detected (Even if No Capping)
Currently, logging only occurs when capping happens. It might be valuable for analysis to also log when consensus is detected even if HTF adjustment was already within bounds. This would help analyze how often consensus occurs vs how often it triggers capping.

3. Test test_extreme_fear_path_with_consensus Has Conditional Assertions
Lines 3267-3273 in the test have assertions inside if conditions, which means they may not run if the conditions aren't met:

if result.score > 0:
    # ...
    if rsi >= 15 and bb >= 20:
        assert htf >= -10, f"HTF should be capped to -10 in extreme fear, got {htf}"

The test might silently pass even if the score isn't positive or consensus isn't detected. Consider either:

  • Using mocks to guarantee the conditions are met (like the other integration tests do)
  • Adding explicit assertions that fail if conditions aren't met

🟢 Verified

  • The capping logic is applied in all three relevant code paths:
    1. Normal HTF bias path (line 1206-1209)
    2. Extreme fear + bearish daily path (line 1157-1159)
    3. Extreme fear + bullish daily path (line 1178-1180)
  • The was_capped return value is correctly ignored (_) since it's only used for testing
  • The extreme_fear_override_applied flag prevents double-capping
  • No changes to protected paths beyond the signal_scorer.py strategy file
  • Type hints are correct (tuple[int, bool])

Conclusion

🟢 Approve - This is a well-implemented fix with good test coverage. The suggestions above are minor improvements that can be addressed in follow-up PRs if desired.

The fix addresses a real issue (HTF overriding unanimous short-term signals) without breaking existing behavior for non-consensus cases. The cap value of ±10 is reasonable - it still allows some HTF influence while preserving the short-term signal direction.


Review by claude[bot]

- Add test_helper_zero_adjustment to cover zero HTF adjustment edge case
- Fix test_extreme_fear_path_with_consensus to use mocks instead of
  conditional assertions, ensuring test coverage is always exercised

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

Review feedback addressed. Please re-review.

Workflow run

@claude
Copy link
Contributor Author

claude bot commented Jan 10, 2026

PR Review: fix(strategy): cap HTF adjustment when short-term indicators show consensus

Overview

This PR addresses issue #342 by capping the HTF (Higher Timeframe) adjustment when RSI and Bollinger indicators both unanimously signal overbought/oversold conditions. The goal is to prevent HTF from completely overriding timely exit/entry signals during short-term indicator consensus.


✅ Strengths

1. Well-structured code organization

  • The helper function _cap_htf_adjustment_for_consensus() is well-designed with clear documentation
  • Named constant SHORT_TERM_CONSENSUS_HTF_CAP = 10 eliminates magic numbers
  • Good separation of concerns between consensus detection and capping logic

2. Comprehensive test coverage

  • 13+ new tests covering helper function edge cases (positive/negative caps, boundaries, custom values)
  • Integration tests for bearish/bullish consensus detection
  • Test for extreme fear path with consensus
  • Good use of mocking to ensure consistent test behavior

3. Clear problem statement and documentation

4. Correct logic flow

  • Consensus detection happens once before HTF adjustment
  • Capping is applied in all three HTF adjustment paths (strong bias, daily-only, extreme fear)
  • extreme_fear_override_applied flag correctly prevents double-capping

🟢 Low Priority Observations

1. Return value unused in all call sites
The helper function returns (capped_adjustment, was_capped) but was_capped is never used:

htf_adjustment, _ = _cap_htf_adjustment_for_consensus(...)

This is fine for now since logging inside the function provides observability, but consider if the boolean is actually needed in the API. No action required - noted for future consideration.

2. Consider adding a metrics counter
For production monitoring, it might be valuable to track how often capping occurs via a counter metric. This would help evaluate the feature's impact over time. No action required - could be a follow-up enhancement.


⚠️ Verification Questions

1. Strong HTF bias path coverage
The capping logic is applied in three places:

  • ✅ Extreme fear with bearish daily (line 1157)
  • ✅ Extreme fear with bullish daily (line 1178)
  • ✅ Non-extreme-fear path (line 1207)

However, the strong HTF bias path (lines 1113-1124, when htf_bias \!= "neutral") applies adjustment but capping only happens later at line 1207 since extreme_fear_override_applied would be False. This is correct behavior - just confirming the logic flow is intentional.

2. Threshold rationale
The consensus thresholds are documented as:

  • RSI ≤ -15 / ≥ 15 (60% of max 25)
  • BB ≤ -20 / ≥ 20 (100% of max 20)

The asymmetry between RSI at 60% and BB at 100% is interesting. Is this intentional based on indicator reliability, or should both use similar thresholds? This is a design question, not a bug.


🔍 Test Execution Note

I was unable to run the test suite directly due to environment constraints, but the test code structure looks correct. The PR description indicates tests pass:

Run full test suite: python3 -m pytest tests/ --ignore=tests/test_coinbase_integration_live.py -v
Verify 149 signal scorer tests pass ✅


Summary

Aspect Rating Notes
Code Quality ✅ Good Clean, well-documented, follows existing patterns
Logic Correctness ✅ Good Capping applied in all HTF paths correctly
Test Coverage ✅ Good 13+ new tests with edge cases
Security ✅ N/A No security implications
Performance ✅ Minimal One extra boolean check per score calculation

Recommendation: Approve 👍

This is a well-implemented, surgical fix that addresses a specific issue without over-engineering. The code is maintainable and thoroughly tested.


🤖 Review by claude[bot]

@TheodorStorm TheodorStorm merged commit 8eb57c0 into develop Jan 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant