-
Notifications
You must be signed in to change notification settings - Fork 3
Add Pattern Recognition & Visualization (Phase 2) #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Pattern Recognition & Visualization (Phase 2) #21
Conversation
Co-authored-by: deepentropy <8287111+deepentropy@users.noreply.github.com>
Co-authored-by: deepentropy <8287111+deepentropy@users.noreply.github.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this 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.
| assert swing_lows[2] == True # Trough at 8 | ||
| assert swing_lows[6] == True # Trough at 7 |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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] == Truewithassert swing_lows[2]assert swing_lows[6] == Truewithassert swing_lows[6]
| 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 |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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) == Truewithprice_within_tolerance(100.0, 102.0, 0.03)price_within_tolerance(100.0, 100.0, 0.01) == Truewithprice_within_tolerance(100.0, 100.0, 0.01)
| 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) |
| assert line['color'] == 'blue' | ||
| assert line['width'] == 2 | ||
| assert line['style'] == 'dashed' | ||
| assert line['extend'] == True |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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'] == Truewithassert line['extend']
| assert line['extend'] == True | |
| assert line['extend'] |
| assert swing_highs[2] == True # Peak at 15 | ||
| assert swing_highs[6] == True # Peak at 16 | ||
| assert swing_highs[0] == False |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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] == Truewithassert swing_highs[2]assert swing_highs[0] == Falsewithassert not swing_highs[0]
| 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] |
|
|
||
| # Show PRZ zone if requested | ||
| if show_prz: | ||
| prz_lower, prz_upper = pattern.prz |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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.
| prz_lower, prz_upper = pattern.prz |
| """ | ||
|
|
||
| from dataclasses import dataclass | ||
| from typing import List, Optional, Tuple |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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.
| from typing import List, Optional, Tuple | |
| from typing import List, Tuple |
| If lwcharts is not installed, graceful degradation is provided. | ||
| """ | ||
|
|
||
| from typing import Any, Dict, List, Optional, Union |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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.
| from typing import Any, Dict, List, Optional, Union | |
| from typing import Any, Dict, List, Optional |
| and markers that can be used with various charting libraries. | ||
| """ | ||
|
|
||
| from typing import Any, Dict, List, Optional, Tuple, Union |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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.
| from typing import Any, Dict, List, Optional, Tuple, Union | |
| from typing import Any, Dict, List, Optional |
| """ | ||
|
|
||
| from typing import Any, Dict, List, Optional, Tuple, Union | ||
| import numpy as np |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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.
| import numpy as np |
| 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, | ||
| ) |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
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.
Implements chart pattern detection with confidence scoring and visualization support via
deepentropy/lwcharts.New Packages
src/numta/patterns/find_swing_highs,find_swing_lows,find_swing_points)src/numta/viz/plot_chart(),plot_pattern(),plot_harmonic()with graceful degradationPandas Accessor
Optional Dependencies
Tests
test_patterns.pyandtest_viz.pyOriginal prompt
This pull request was created as a result of the following prompt from Copilot chat.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.