Skip to content
Back to skills

Technical Support Resistance

ASecurity

'"Implements technical levels where price tends to pause or reverse for

  • 4 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added June 12, 2026
documentationpythongotestingdocumentation

Security analysis

A100/100

Scanned June 12, 2026

npx -y skills add paulpas/agent-skill-router --skill technical-support-resistance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Technical Support Resistance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Technical Support Resistance
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/paulpas-technical-support-resistance/badge)](https://www.skillsdirectory.com/skills/paulpas-technical-support-resistance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---




name: technical-support-resistance
compatibility: opencode
completeness: 95
content-types:
- code
- guidance
- config
- do-dont
description: '"Implements technical levels where price tends to pause or reverse for
  risk management and algorithmic trading execution."'
license: MIT
maturity: stable
metadata:
  domain: trading
  output-format: code
  related-skills: fundamentals-trading-plan, technical-cycle-analysis
  role: implementation
  scope: implementation
  triggers: levels, price, technical support resistance, technical-support-resistance,
    where
  archetypes:
  - tactical
  anti_triggers:
  - brainstorming
  - vague ideation
  - no risk management
  response_profile:
    verbosity: low
    directive_strength: high
    abstraction_level: operational
version: "1.0.0"




---




**Role:** Identify and validate key S/R levels for entry, exit, and stop placement

**Philosophy:** Support and resistance represent collective memory and psychological barriers in the market

## Key Principles

1. **Confluence**: Multiple indicators confirming same level increases validity
2. **Time Integration**: Levels tested multiple times gain strength
3. **Volume Confirmation**: High volume at level indicates institutional interest
4. **Timeframe Hierarchy**: Higher timeframe levels override lower timeframe
5. **Breakout Validation**: Breakouts need follow-through to be valid

## Implementation Guidelines

### Structure
- Core logic: technical_analysis/support_resistance.py
- Helper functions: technical_analysis/level_analysis.py
- Tests: tests/test_support_resistance.py

### Patterns to Follow
- Cluster levels by price bins
- Track test frequency and volume at each level
- Calculate level strength score

## Adherence Checklist
Before completing your task, verify:
- [ ] Support/resistance levels update in real-time
- [ ] Level strength incorporates volume, frequency, and recency
- [ ] Breakout confirmation requires 2x average volume
- [ ] False breakouts are detected and flagged
- [ ] Level retests are tracked with success rate


Relative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.

## Python Implementation

```python
import numpy as np
import pandas as pd
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
from datetime import datetime

@dataclass
class SupportLevel:
    """A support level with metadata."""
    price: float
    strength: float  # 0-1 score
    test_count: int
    volume_at_level: float
    last_test: datetime
    confirmed: bool

@dataclass
class ResistanceLevel:
    """A resistance level with metadata."""
    price: float
    strength: float  # 0-1 score
    test_count: int
    volume_at_level: float
    last_test: datetime
    broken: bool

class SupportResistanceAnalyzer:
    """Identifies and tracks support and resistance levels."""
    
    def __init__(self, bin_size: float = 0.01, min_tests: int = 2):
        self.bin_size = bin_size
        self.min_tests = min_tests
    
    def identify_support_levels(
        self, candles: pd.DataFrame, lookback: int = 100
    ) -> List[SupportLevel]:
        """Identify key support levels from historical data."""
        recent_candles = candles.tail(lookback)
        support_levels = []
        
        # Find swing lows
        for i in range(1, len(recent_candles) - 1):
            low = recent_candles['low'].iloc[i]
            prev_low = recent_candles['low'].iloc[i-1]
            next_low = recent_candles['low'].iloc[i+1]
            
            # Swing low: lower than neighbors
            if low < prev_low and low < next_low:
                support_levels.append({
                    'price': low,
                    'volume': recent_candles['volume'].iloc[i],
                    'index': i
                })
        
        # Cluster similar support levels
        clustered = self._cluster_levels(support_levels)
        
        # Calculate strength for each level
        result = []
        for level_data in clustered:
            strength = self._calculate_support_strength(
                candles, level_data['price'], level_data['count']
            )
            result.append(SupportLevel(
                price=level_data['price'],
                strength=strength,
                test_count=level_data['count'],
                volume_at_level=level_data['total_volume'],
                last_test=candles.index[level_data['last_index']],
                confirmed=strength > 0.5
            ))
        
        return sorted(result, key=lambda x: x.price, reverse=True)
    
    def identify_resistance_levels(
        self, candles: pd.DataFrame, lookback: int = 100
    ) -> List[ResistanceLevel]:
        """Identify key resistance levels from historical data."""
        recent_candles = candles.tail(lookback)
        resistance_levels = []
        
        # Find swing highs
        for i in range(1, len(recent_candles) - 1):
            high = recent_candles['high'].iloc[i]
            prev_high = recent_candles['high'].iloc[i-1]
            next_high = recent_candles['high'].iloc[i+1]
            
            # Swing high: higher than neighbors
            if high > prev_high and high > next_high:
                resistance_levels.append({
                    'price': high,
                    'volume': recent_candles['volume'].iloc[i],
                    'index': i
                })
        
        # Cluster similar resistance levels
        clustered = self._cluster_levels(resistance_levels)
        
        # Calculate strength for each level
        result = []
        for level_data in clustered:
            strength = self._calculate_resistance_strength(
                candles, level_data['price'], level_data['count']
            )
            result.append(ResistanceLevel(
                price=level_data['price'],
                strength=strength,
                test_count=level_data['count'],
                volume_at_level=level_data['total_volume'],
                last_test=candles.index[level_data['last_index']],
                broken=False
            ))
        
        return sorted(result, key=lambda x: x.price)
    
    def _cluster_levels(
        self, levels: List[Dict], tolerance: float = None
    ) -> List[Dict]:
        """Cluster nearby support/resistance levels."""
        if tolerance is None:
            tolerance = self.bin_size * 3
        
        if not levels:
            return []
        
        # Sort by price
        sorted_levels = sorted(levels, key=lambda x: x['price'])
        clusters = []
        
        current_cluster = {
            'prices': [sorted_levels[0]['price']],
            'volumes': [sorted_levels[0]['volume']],
            'indices': [sorted_levels[0]['index']],
            'total_volume': sorted_levels[0]['volume']
        }
        
        for level in sorted_levels[1:]:
            if level['price'] - current_cluster['prices'][-1] <= tolerance:
                # Add to current cluster
                current_cluster['prices'].append(level['price'])
                current_cluster['volumes'].append(level['volume'])
                current_cluster['indices'].append(level['index'])
                current_cluster['total_volume'] += level['volume']
            else:
                # Save current cluster and start new
                clusters.append({
                    'price': np.mean(current_cluster['prices']),
                    'count': len(current_cluster['prices']),
                    'last_index': current_cluster['indices'][-1],
                    'total_volume': current_cluster['total_volume']
                })
                current_cluster = {
                    'prices': [level['price']],
                    'volumes': [level['volume']],
                    'indices': [level['index']],
                    'total_volume': level['volume']
                }
        
        # Don't forget last cluster
        clusters.append({
            'price': np.mean(current_cluster['prices']),
            'count': len(current_cluster['prices']),
            'last_index': current_cluster['indices'][-1],
            'total_volume': current_cluster['total_volume']
        })
        
        return clusters
    
    def _calculate_support_strength(
        self, candles: pd.DataFrame, price: float, test_count: int
    ) -> float:
        """Calculate strength score for support level."""
        strength = 0
        
        # Test count factor (more tests = stronger)
        test_score = min(test_count / 5, 1.0) * 0.3
        
        # Volume factor (higher volume = stronger)
        recent_vol = candles['volume'].tail(50).mean()
        level_vol = candles[candles['low'].between(price - 0.01, price + 0.01)]['volume'].sum()
        volume_score = min(level_vol / (recent_vol * 10), 1.0) * 0.3
        
        # Recency factor (more recent tests = stronger)
        if test_count > 0:
            recent_tests = candles[candles['low'] <= price + 0.01].tail(10)
            recency_score = len(recent_tests) / 10 * 0.4
        else:
            recency_score = 0
        
        return min(test_score + volume_score + recency_score, 1.0)
    
    def _calculate_resistance_strength(
        self, candles: pd.DataFrame, price: float, test_count: int
    ) -> float:
        """Calculate strength score for resistance level."""
        strength = 0
        
        # Test count factor
        test_score = min(test_count / 5, 1.0) * 0.3
        
        # Volume factor
        recent_vol = candles['volume'].tail(50).mean()
        level_vol = candles[candles['high'].between(price - 0.01, price + 0.01)]['volume'].sum()
        volume_score = min(level_vol / (recent_vol * 10), 1.0) * 0.3
        
        # Recency factor
        if test_count > 0:
            recent_tests = candles[candles['high'] >= price - 0.01].tail(10)
            recency_score = len(recent_tests) / 10 * 0.4
        else:
            recency_score = 0
        
        return min(test_score + volume_score + recency_score, 1.0)
```

---

---



### Pattern 2: Risk-Managed Trading Logic with Validation

```python
from __future__ import annotations

import logging
from dataclasses import dataclass
from typing import Optional


logger = logging.getLogger(__name__)


@dataclass(frozen=True)
class TradeSignal:
    """Immutable trade signal with all required validation constraints."""
    symbol: str
    side: str  # "buy" or "sell"
    price: float
    quantity: float
    confidence: float  # 0.0 to 1.0
    reason: str

    def validate(self) -> bool:
        """Validate that the trade signal meets all business constraints."""
        if self.quantity <= 0:
            raise ValueError(f"Quantity must be positive, got {self.quantity}")
        if self.price <= 0:
            raise ValueError(f"Price must be positive, got {self.price}")
        if not 0.0 <= self.confidence <= 1.0:
            raise ValueError(f"Confidence must be between 0 and 1, got {self.confidence}")
        return True


def generate_trade_signal(
    symbol: str,
    side: str,
    price: float,
    quantity: float,
    confidence: float,
    reason: str,
) -> TradeSignal:
    """Generate a validated trade signal with guard clause checks."""
    if side not in ("buy", "sell"):
        raise ValueError(f"Invalid side '{side}', must be 'buy' or 'sell'")

    signal = TradeSignal(
        symbol=symbol,
        side=side,
        price=price,
        quantity=quantity,
        confidence=confidence,
        reason=reason,
    )
    signal.validate()
    logger.info("Trade signal generated: %s %s %.4f @ %.2f (confidence=%.2f)",
                 symbol, side, quantity, price, confidence)
    return signal


def execute_with_risk_check(signal: TradeSignal, max_position_pct: float = 0.05) -> dict:
    """Execute a trade signal after applying risk management checks."""
    adjusted_quantity = signal.quantity
    if signal.side == "buy" and signal.quantity > max_position_pct:
        logger.warning("Position %s exceeds max %.1f%% — capping to %.4f",
                        signal.symbol, max_position_pct * 100, max_position_pct)
        adjusted_quantity = max_position_pct

    return {
        "symbol": signal.symbol,
        "side": signal.side,
        "price": signal.price,
        "quantity": adjusted_quantity,
        "capped": adjusted_quantity < signal.quantity,
        "confidence": signal.confidence,
        "status": "submitted",
    }
```

## Constraints

### MUST DO
- Implement indicator calculations using rolling windows with explicit lookback periods; never use full-history data for online indicators
- Validate signal generation by confirming alignment across multiple independent indicators before acting on a single signal
- Calculate all price-based indicators (SMA, EMA, RSI) on closing prices unless specifically designed for tick data
- Include proper handling of missing/NaN candles in indicator pipelines — forward-fill only within session boundaries
- Log signal generation with the full context window of indicator values that led to each signal

### MUST NOT DO
- Do not use look-ahead bias: never reference future bars or prices when calculating indicators during backtesting
- Avoid recalculating all indicators from scratch on every tick — maintain running state for efficiency
- Never combine indicators with different timeframes without explicit resampling and clear documentation of the alignment logic
- Do not generate signals based on a single indicator crossover; require confirmation from price action or volume
- Avoid hardcoding parameter values (e.g., RSI period = 14) without testing regime-specific optima


## Live References

> Authoritative documentation links for this skill's domain. The model follows markdown links at load time to resolve external references and inline content.

- [Support and Resistance Explained](https://www.investopedia.com/terms/s/support_resistance.asp)
- [Pivot Points and Price Levels](https://www.investopedia.com/articles/trading/07/pivot-points.asp)
- [Drawing Trendlines Effectively](https://www.investopedia.com/articles/trading/06/drawing-trendlines.asp)
- [Breakout Trading Strategies](https://www.investopedia.com/trading/breakouts/)
- [Support Resistance with Volume Profiles](https://www.investopedia.com/articles/trading/11/volume-profile.asp)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.