Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 1, 2025

Implements chart pattern detection with confidence scoring and visualization support via deepentropy/lwcharts.

New Packages

src/numta/patterns/

  • swing.py: Swing high/low detection (find_swing_highs, find_swing_lows, find_swing_points)
  • utils.py: Fibonacci retracement/extension, trendline fitting, confidence scoring
  • chart_patterns.py: Head & Shoulders, Double/Triple Top/Bottom, Triangles, Wedges, Flags, VCP
  • harmonic_patterns.py: Gartley, Butterfly, Bat, Crab patterns with standard Fibonacci ratios

src/numta/viz/

  • lwcharts_adapter.py: plot_chart(), plot_pattern(), plot_harmonic() with graceful degradation
  • pattern_markers.py: Annotation helpers for markers, trendlines, zones

Pandas Accessor

# Chart patterns
patterns = df.ta.find_patterns(pattern_type='double', order=5)

# Harmonic patterns  
harmonics = df.ta.find_harmonic_patterns(patterns=['gartley', 'bat'])

# Visualization
df.ta.plot(indicators={'SMA_20': df.ta.sma(20)}, patterns=patterns)

Optional Dependencies

viz = ["pandas>=1.3.0", "lwcharts>=0.1.0"]
patterns = ["pandas>=1.3.0"]
full = ["pandas>=1.3.0", "lwcharts>=0.1.0", "numba>=0.56.0"]

Tests

  • 58 new tests in test_patterns.py and test_viz.py
  • All 302 tests pass
Original prompt

Phase 2: Pattern Recognition & Visualization

Overview

Implement chart pattern detection capabilities with visualization support using the deepentropy/lwcharts library (TradingView Lightweight Charts for Jupyter notebooks).

Deliverables

1. Chart Pattern Detection Module (src/numta/patterns/)

Create a new patterns subpackage:

src/numta/patterns/
├── __init__.py
├── chart_patterns.py        # Head & Shoulders, Double Top/Bottom, Triangles, Wedges, Flags, VCP
├── harmonic_patterns.py     # Gartley, Butterfly, Bat, Crab patterns
├── swing.py                 # Swing high/low detection
└── utils.py                 # Fibonacci levels, trendline fitting

Swing Detection (swing.py)

def find_swing_highs(high: np.ndarray, order: int = 5) -> np.ndarray
def find_swing_lows(low: np.ndarray, order: int = 5) -> np.ndarray
def find_swing_points(high: np.ndarray, low: np.ndarray, order: int = 5) -> tuple

Chart Patterns (chart_patterns.py)

Implement pattern dataclasses and detection functions:

  • HeadShouldersPattern + detect_head_shoulders(), detect_inverse_head_shoulders()
  • DoublePattern + detect_double_top(), detect_double_bottom()
  • TriplePattern + detect_triple_top(), detect_triple_bottom()
  • TrianglePattern + detect_triangle() (ascending, descending, symmetrical)
  • WedgePattern + detect_wedge() (rising, falling)
  • FlagPattern + detect_flag() (bull flag, bear flag, pennant)
  • VCPPattern + detect_vcp() (Volatility Contraction Pattern)

Each pattern should include: pattern_type, key points (indices + prices), trendlines/necklines, breakout levels, start/end indices, and confidence score (0-1).

Harmonic Patterns (harmonic_patterns.py)

@dataclass
class HarmonicPattern:
    pattern_type: str  # 'gartley', 'butterfly', 'bat', 'crab'
    X, A, B, C, D: tuple[int, float]  # Points with (index, price)
    direction: str  # 'bullish' or 'bearish'
    XA_retracement, AB_retracement, BC_retracement, CD_retracement: float
    prz: tuple[float, float]  # Potential Reversal Zone
    confidence: float

def detect_gartley(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_butterfly(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_bat(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_crab(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_harmonic_patterns(high, low, close, patterns=None, tolerance=0.02) -> list[HarmonicPattern]

Use standard Fibonacci ratios for each pattern type.

Utilities (utils.py)

def fibonacci_retracement(start: float, end: float) -> dict[str, float]
def fibonacci_extension(start: float, end: float, retracement: float) -> dict[str, float]
def fit_trendline(points: list[tuple[int, float]]) -> tuple[float, float]
def calculate_pattern_confidence(pattern_data: dict) -> float

2. Visualization Module (src/numta/viz/)

src/numta/viz/
├── __init__.py
├── lwcharts_adapter.py      # Integration with deepentropy/lwcharts
└── pattern_markers.py       # Pattern annotation helpers
def plot_chart(df, indicators=None, volume=True, height=400, width=800)
def plot_pattern(df, patterns, show_annotations=True, show_trendlines=True)
def plot_harmonic(df, patterns, show_fibonacci=True, show_prz=True)

3. Pandas Accessor Extension

Add to TAAccessor class in src/numta/pandas_ext.py:

def find_patterns(self, pattern_type='all', order=5, tolerance=0.03) -> list
def find_harmonic_patterns(self, patterns=None, tolerance=0.02) -> list[HarmonicPattern]
def plot(self, indicators=None, patterns=None, volume=True, height=400, width=800)

4. Update pyproject.toml

[project.optional-dependencies]
viz = ["pandas>=1.3.0", "lwcharts>=0.1.0"]
patterns = ["pandas>=1.3.0"]
full = ["pandas>=1.3.0", "lwcharts>=0.1.0", "numba>=0.56.0"]

5. Update src/numta/__init__.py

Export all pattern detection functions and dataclasses.

6. Tests

Create tests/test_patterns.py and tests/test_viz.py with comprehensive coverage.

7. Documentation

Update README.md with Pattern Recognition section including examples.

Acceptance Criteria

  1. All chart patterns detected correctly with confidence scores
  2. Harmonic patterns use correct Fibonacci ratios
  3. Visualization works in Jupyter notebooks via lwcharts
  4. Pandas .ta.find_patterns() and .ta.plot() methods work
  5. Tests pass for all pattern types
  6. Graceful degradation when lwcharts not installed

This pull request was created as a result of the following prompt from Copilot chat.

Phase 2: Pattern Recognition & Visualization

Overview

Implement chart pattern detection capabilities with visualization support using the deepentropy/lwcharts library (TradingView Lightweight Charts for Jupyter notebooks).

Deliverables

1. Chart Pattern Detection Module (src/numta/patterns/)

Create a new patterns subpackage:

src/numta/patterns/
├── __init__.py
├── chart_patterns.py        # Head & Shoulders, Double Top/Bottom, Triangles, Wedges, Flags, VCP
├── harmonic_patterns.py     # Gartley, Butterfly, Bat, Crab patterns
├── swing.py                 # Swing high/low detection
└── utils.py                 # Fibonacci levels, trendline fitting

Swing Detection (swing.py)

def find_swing_highs(high: np.ndarray, order: int = 5) -> np.ndarray
def find_swing_lows(low: np.ndarray, order: int = 5) -> np.ndarray
def find_swing_points(high: np.ndarray, low: np.ndarray, order: int = 5) -> tuple

Chart Patterns (chart_patterns.py)

Implement pattern dataclasses and detection functions:

  • HeadShouldersPattern + detect_head_shoulders(), detect_inverse_head_shoulders()
  • DoublePattern + detect_double_top(), detect_double_bottom()
  • TriplePattern + detect_triple_top(), detect_triple_bottom()
  • TrianglePattern + detect_triangle() (ascending, descending, symmetrical)
  • WedgePattern + detect_wedge() (rising, falling)
  • FlagPattern + detect_flag() (bull flag, bear flag, pennant)
  • VCPPattern + detect_vcp() (Volatility Contraction Pattern)

Each pattern should include: pattern_type, key points (indices + prices), trendlines/necklines, breakout levels, start/end indices, and confidence score (0-1).

Harmonic Patterns (harmonic_patterns.py)

@dataclass
class HarmonicPattern:
    pattern_type: str  # 'gartley', 'butterfly', 'bat', 'crab'
    X, A, B, C, D: tuple[int, float]  # Points with (index, price)
    direction: str  # 'bullish' or 'bearish'
    XA_retracement, AB_retracement, BC_retracement, CD_retracement: float
    prz: tuple[float, float]  # Potential Reversal Zone
    confidence: float

def detect_gartley(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_butterfly(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_bat(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_crab(high, low, close, tolerance=0.02) -> list[HarmonicPattern]
def detect_harmonic_patterns(high, low, close, patterns=None, tolerance=0.02) -> list[HarmonicPattern]

Use standard Fibonacci ratios for each pattern type.

Utilities (utils.py)

def fibonacci_retracement(start: float, end: float) -> dict[str, float]
def fibonacci_extension(start: float, end: float, retracement: float) -> dict[str, float]
def fit_trendline(points: list[tuple[int, float]]) -> tuple[float, float]
def calculate_pattern_confidence(pattern_data: dict) -> float

2. Visualization Module (src/numta/viz/)

src/numta/viz/
├── __init__.py
├── lwcharts_adapter.py      # Integration with deepentropy/lwcharts
└── pattern_markers.py       # Pattern annotation helpers
def plot_chart(df, indicators=None, volume=True, height=400, width=800)
def plot_pattern(df, patterns, show_annotations=True, show_trendlines=True)
def plot_harmonic(df, patterns, show_fibonacci=True, show_prz=True)

3. Pandas Accessor Extension

Add to TAAccessor class in src/numta/pandas_ext.py:

def find_patterns(self, pattern_type='all', order=5, tolerance=0.03) -> list
def find_harmonic_patterns(self, patterns=None, tolerance=0.02) -> list[HarmonicPattern]
def plot(self, indicators=None, patterns=None, volume=True, height=400, width=800)

4. Update pyproject.toml

[project.optional-dependencies]
viz = ["pandas>=1.3.0", "lwcharts>=0.1.0"]
patterns = ["pandas>=1.3.0"]
full = ["pandas>=1.3.0", "lwcharts>=0.1.0", "numba>=0.56.0"]

5. Update src/numta/__init__.py

Export all pattern detection functions and dataclasses.

6. Tests

Create tests/test_patterns.py and tests/test_viz.py with comprehensive coverage.

7. Documentation

Update README.md with Pattern Recognition section including examples.

Acceptance Criteria

  1. All chart patterns detected correctly with confidence scores
  2. Harmonic patterns use correct Fibonacci ratios
  3. Visualization works in Jupyter notebooks via lwcharts
  4. Pandas .ta.find_patterns() and .ta.plot() methods work
  5. Tests pass for all pattern types
  6. Graceful degradation when lwcharts not installed

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits December 1, 2025 09:27
Co-authored-by: deepentropy <8287111+deepentropy@users.noreply.github.com>
Co-authored-by: deepentropy <8287111+deepentropy@users.noreply.github.com>
Copilot AI changed the title [WIP] Add chart pattern detection and visualization support Add Pattern Recognition & Visualization (Phase 2) Dec 1, 2025
Copilot AI requested a review from deepentropy December 1, 2025 09:35
@deepentropy deepentropy marked this pull request as ready for review December 1, 2025 09:39
Copilot AI review requested due to automatic review settings December 1, 2025 09:39
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@deepentropy deepentropy merged commit 1ddc032 into main Dec 1, 2025
14 checks passed
@deepentropy deepentropy deleted the copilot/add-pattern-recognition-visualization branch December 1, 2025 09:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements Phase 2 pattern recognition and visualization capabilities for the numta library, adding comprehensive chart pattern detection with confidence scoring and optional visualization support via the lwcharts library.

Summary: The PR successfully adds pattern detection for classic chart patterns (Head & Shoulders, Double/Triple Top/Bottom, Triangles, Wedges, Flags, VCP) and harmonic patterns (Gartley, Butterfly, Bat, Crab) with Fibonacci ratio validation. It also provides visualization integration and extends the pandas accessor with .ta.find_patterns(), .ta.find_harmonic_patterns(), and .ta.plot() methods.

Key Changes:

  • New src/numta/patterns/ package with swing detection, pattern utilities, chart patterns, and harmonic patterns
  • New src/numta/viz/ package with lwcharts adapter and pattern marker utilities
  • Extended pandas accessor with pattern detection and plotting methods
  • Added optional dependencies for visualization and pattern features

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/numta/patterns/swing.py Swing high/low detection with support for higher/lower highs/lows
src/numta/patterns/utils.py Fibonacci calculations, trendline fitting, pattern confidence scoring
src/numta/patterns/chart_patterns.py Detection for 7 classic chart patterns with dataclasses
src/numta/patterns/harmonic_patterns.py Detection for 4 harmonic patterns with standard Fibonacci ratios
src/numta/viz/lwcharts_adapter.py Integration with lwcharts library with graceful degradation
src/numta/viz/pattern_markers.py Helper functions for creating pattern annotations
src/numta/pandas_ext.py Added .ta.find_patterns(), .ta.find_harmonic_patterns(), .ta.plot() methods
tests/test_patterns.py 58 new tests for pattern detection functionality
tests/test_viz.py Comprehensive tests for visualization and marker creation
pyproject.toml Added viz, patterns, and full optional dependency groups
README.md Documentation for pattern recognition and visualization features

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

Comment on lines +74 to +75
assert swing_lows[2] == True # Trough at 8
assert swing_lows[6] == True # Trough at 7
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using explicit comparison with boolean literals. Instead of == True, use the value directly.

Replace:

  • assert swing_lows[2] == True with assert swing_lows[2]
  • assert swing_lows[6] == True with assert swing_lows[6]

Copilot uses AI. Check for mistakes.
Comment on lines +160 to +162
assert price_within_tolerance(100.0, 102.0, 0.03) == True
assert price_within_tolerance(100.0, 110.0, 0.03) == False
assert price_within_tolerance(100.0, 100.0, 0.01) == True
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using explicit comparison with boolean literals. Replace == True with the value directly.

Replace:

  • price_within_tolerance(100.0, 102.0, 0.03) == True with price_within_tolerance(100.0, 102.0, 0.03)
  • price_within_tolerance(100.0, 100.0, 0.01) == True with price_within_tolerance(100.0, 100.0, 0.01)
Suggested change
assert price_within_tolerance(100.0, 102.0, 0.03) == True
assert price_within_tolerance(100.0, 110.0, 0.03) == False
assert price_within_tolerance(100.0, 100.0, 0.01) == True
assert price_within_tolerance(100.0, 102.0, 0.03)
assert not price_within_tolerance(100.0, 110.0, 0.03)
assert price_within_tolerance(100.0, 100.0, 0.01)

Copilot uses AI. Check for mistakes.
assert line['color'] == 'blue'
assert line['width'] == 2
assert line['style'] == 'dashed'
assert line['extend'] == True
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using explicit comparison with boolean literals. Replace == True with the value directly.

Replace:

  • assert line['extend'] == True with assert line['extend']
Suggested change
assert line['extend'] == True
assert line['extend']

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +64
assert swing_highs[2] == True # Peak at 15
assert swing_highs[6] == True # Peak at 16
assert swing_highs[0] == False
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using explicit comparison with boolean literals. Instead of == True, use the value directly. Instead of == False, use not value.

Replace:

  • assert swing_highs[2] == True with assert swing_highs[2]
  • assert swing_highs[0] == False with assert not swing_highs[0]
Suggested change
assert swing_highs[2] == True # Peak at 15
assert swing_highs[6] == True # Peak at 16
assert swing_highs[0] == False
assert swing_highs[2] # Peak at 15
assert swing_highs[6] # Peak at 16
assert not swing_highs[0]

Copilot uses AI. Check for mistakes.

# Show PRZ zone if requested
if show_prz:
prz_lower, prz_upper = pattern.prz
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable prz_lower is not used.

Suggested change
prz_lower, prz_upper = pattern.prz

Copilot uses AI. Check for mistakes.
"""

from dataclasses import dataclass
from typing import List, Optional, Tuple
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'Optional' is not used.

Suggested change
from typing import List, Optional, Tuple
from typing import List, Tuple

Copilot uses AI. Check for mistakes.
If lwcharts is not installed, graceful degradation is provided.
"""

from typing import Any, Dict, List, Optional, Union
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'Union' is not used.

Suggested change
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional

Copilot uses AI. Check for mistakes.
and markers that can be used with various charting libraries.
"""

from typing import Any, Dict, List, Optional, Tuple, Union
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'Union' is not used.
Import of 'Tuple' is not used.

Suggested change
from typing import Any, Dict, List, Optional, Tuple, Union
from typing import Any, Dict, List, Optional

Copilot uses AI. Check for mistakes.
"""

from typing import Any, Dict, List, Optional, Tuple, Union
import numpy as np
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'np' is not used.

Suggested change
import numpy as np

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +48
from numta.patterns import (
# Swing detection
find_swing_highs,
find_swing_lows,
find_swing_points,
get_swing_high_indices,
get_swing_low_indices,
# Utilities
fibonacci_retracement,
fibonacci_extension,
fit_trendline,
price_within_tolerance,
calculate_pattern_confidence,
# Chart patterns
detect_head_shoulders,
detect_inverse_head_shoulders,
detect_double_top,
detect_double_bottom,
detect_triple_top,
detect_triple_bottom,
detect_triangle,
detect_wedge,
detect_flag,
detect_vcp,
# Harmonic patterns
detect_gartley,
detect_butterfly,
detect_bat,
detect_crab,
detect_harmonic_patterns,
# Dataclasses
HeadShouldersPattern,
DoublePattern,
TriplePattern,
TrianglePattern,
WedgePattern,
FlagPattern,
VCPPattern,
HarmonicPattern,
)
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'get_swing_low_indices' is not used.

Copilot uses AI. Check for mistakes.
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.

2 participants