narrata 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. narrata-0.1.0/.gitignore +23 -0
  2. narrata-0.1.0/LICENSE +21 -0
  3. narrata-0.1.0/PKG-INFO +164 -0
  4. narrata-0.1.0/README.md +137 -0
  5. narrata-0.1.0/narrata/__init__.py +90 -0
  6. narrata-0.1.0/narrata/analysis/__init__.py +49 -0
  7. narrata-0.1.0/narrata/analysis/indicators.py +440 -0
  8. narrata-0.1.0/narrata/analysis/patterns.py +199 -0
  9. narrata-0.1.0/narrata/analysis/regimes.py +144 -0
  10. narrata-0.1.0/narrata/analysis/summary.py +105 -0
  11. narrata-0.1.0/narrata/analysis/support_resistance.py +129 -0
  12. narrata-0.1.0/narrata/analysis/symbolic.py +207 -0
  13. narrata-0.1.0/narrata/composition/__init__.py +5 -0
  14. narrata-0.1.0/narrata/composition/narrate.py +117 -0
  15. narrata-0.1.0/narrata/compression/__init__.py +5 -0
  16. narrata-0.1.0/narrata/compression/digits.py +24 -0
  17. narrata-0.1.0/narrata/exceptions.py +13 -0
  18. narrata-0.1.0/narrata/formatting/__init__.py +5 -0
  19. narrata-0.1.0/narrata/formatting/serializers.py +53 -0
  20. narrata-0.1.0/narrata/mcp_api.py +428 -0
  21. narrata-0.1.0/narrata/py.typed +1 -0
  22. narrata-0.1.0/narrata/rendering/__init__.py +5 -0
  23. narrata-0.1.0/narrata/rendering/sparkline.py +76 -0
  24. narrata-0.1.0/narrata/types.py +93 -0
  25. narrata-0.1.0/narrata/validation/__init__.py +5 -0
  26. narrata-0.1.0/narrata/validation/ohlcv.py +90 -0
  27. narrata-0.1.0/pyproject.toml +92 -0
  28. narrata-0.1.0/tests/conftest.py +30 -0
  29. narrata-0.1.0/tests/test_digits.py +17 -0
  30. narrata-0.1.0/tests/test_formatting.py +34 -0
  31. narrata-0.1.0/tests/test_import_boundaries.py +45 -0
  32. narrata-0.1.0/tests/test_indicators.py +121 -0
  33. narrata-0.1.0/tests/test_mcp_api.py +76 -0
  34. narrata-0.1.0/tests/test_narrate.py +119 -0
  35. narrata-0.1.0/tests/test_patterns.py +141 -0
  36. narrata-0.1.0/tests/test_public_api.py +40 -0
  37. narrata-0.1.0/tests/test_regimes.py +71 -0
  38. narrata-0.1.0/tests/test_sparkline.py +36 -0
  39. narrata-0.1.0/tests/test_summary.py +54 -0
  40. narrata-0.1.0/tests/test_support_resistance.py +15 -0
  41. narrata-0.1.0/tests/test_symbolic.py +46 -0
  42. narrata-0.1.0/tests/test_validation.py +57 -0
@@ -0,0 +1,23 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ src/*/.venv/
5
+ .uv-cache/
6
+ .mypy_cache/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .coverage
10
+ coverage.xml
11
+ htmlcov/
12
+ dist/
13
+ build/
14
+ *.egg-info/
15
+ .DS_Store
16
+ .vscode/
17
+
18
+ # Custom
19
+ PROPOSAL.md
20
+ DEVELOPER.md
21
+ .agents
22
+ uv.lock
23
+ src/*/uv.lock
narrata-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
narrata-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: narrata
3
+ Version: 0.1.0
4
+ Summary: LLM-oriented narration and compression for time series data
5
+ Author-email: Marcin Miklitz <11770857+marcinmiklitz@users.noreply.github.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: numpy<3.0.0,>=1.24
10
+ Requires-Dist: pandas<4.0.0,>=2.0.0
11
+ Requires-Dist: scipy>=1.10.0
12
+ Requires-Dist: toons>=0.4.2
13
+ Provides-Extra: all
14
+ Requires-Dist: pandas-ta-openbb>=0.4.23; extra == 'all'
15
+ Requires-Dist: ruptures>=1.1.9; (python_version < '3.14') and extra == 'all'
16
+ Requires-Dist: tslearn>=0.6.4; extra == 'all'
17
+ Provides-Extra: indicators
18
+ Requires-Dist: pandas-ta-openbb>=0.4.23; extra == 'indicators'
19
+ Provides-Extra: patterns
20
+ Requires-Dist: pandas-ta-openbb>=0.4.23; extra == 'patterns'
21
+ Provides-Extra: regimes
22
+ Requires-Dist: ruptures>=1.1.9; (python_version < '3.14') and extra == 'regimes'
23
+ Provides-Extra: symbolic
24
+ Requires-Dist: ruptures>=1.1.9; (python_version < '3.14') and extra == 'symbolic'
25
+ Requires-Dist: tslearn>=0.6.4; extra == 'symbolic'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # narrata
29
+
30
+ `narrata` turns OHLCV price series into compact, deterministic text summaries optimized for LLM context.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install narrata
36
+ ```
37
+
38
+ Install optional backends:
39
+
40
+ ```bash
41
+ pip install "narrata[all]"
42
+ ```
43
+
44
+ Requires Python 3.11+ and pandas 2.0+.
45
+
46
+ ## Quickstart
47
+
48
+ ```python
49
+ import numpy as np
50
+ import pandas as pd
51
+
52
+ from narrata import narrate
53
+
54
+ n = 120
55
+ dates = pd.date_range("2025-01-01", periods=n, freq="D")
56
+ rng = np.random.default_rng(7)
57
+ close = np.linspace(140.0, 175.0, n) + rng.normal(0.0, 1.0, n)
58
+ open_ = close + rng.normal(0.0, 0.6, n)
59
+ high = np.maximum(open_, close) + np.abs(rng.normal(0.7, 0.2, n))
60
+ low = np.minimum(open_, close) - np.abs(rng.normal(0.7, 0.2, n))
61
+ volume = rng.integers(900_000, 2_100_000, n)
62
+
63
+ df = pd.DataFrame(
64
+ {"Open": open_, "High": high, "Low": low, "Close": close, "Volume": volume},
65
+ index=dates,
66
+ )
67
+ df.attrs["ticker"] = "AAPL"
68
+
69
+ print(narrate(df))
70
+ ```
71
+
72
+ Example output:
73
+
74
+ ```text
75
+ AAPL (120 pts, daily): ▁▁▂▂▂▃▃▄▄▄▄▅▆▆▆▆▇▇██
76
+ Date range: 2025-01-01 to 2025-04-30
77
+ Range: [$139.99, $175.68] Mean: $157.35 Std: $10.33
78
+ Start: $140.00 End: $175.19 Change: +25.14%
79
+ Regime: Uptrend since 2025-01-02 (low volatility)
80
+ RSI(14): 65.1 (neutral-bullish) MACD: bullish crossover 1 day ago
81
+ BB: near upper band
82
+ Volume: 0.98x 20-day avg (average)
83
+ Volatility: 23rd percentile (low)
84
+ SAX(16): aaabbccdeeffgggh
85
+ Patterns: Ascending triangle forming since 2025-03-02
86
+ Candlestick: Doji on 2025-04-29
87
+ Support: $145.13 (13 touches), $139.99 (6 touches) Resistance: $175.68 (3 touches)
88
+ ```
89
+
90
+ ## Fallback vs extras (same input)
91
+
92
+ Using the same deterministic 252-point dataset:
93
+
94
+ Fallback-only (`pip install narrata`):
95
+
96
+ ```text
97
+ AAPL (252 pts, business-daily): ▁▂▁▂▂▃▃▃▄▄▄▅▆▆▆▆▇▇▇█
98
+ Date range: 2024-01-02 to 2024-12-18
99
+ Range: [$140.61, $201.32] Mean: $170.44 Std: $17.52
100
+ Start: $141.05 End: $201.32 Change: +42.73%
101
+ Regime: Uptrend since 2024-12-10 (low volatility)
102
+ RSI(14): 72.9 (overbought) MACD: bullish crossover 7 days ago
103
+ BB: above upper band
104
+ SMA 50/200: golden cross
105
+ Volume: 0.95x 20-day avg (average)
106
+ Volatility: 1st percentile (extremely low)
107
+ SAX(16): aaabbcdeefggghhh
108
+ Patterns: Ascending triangle forming since 2024-09-26
109
+ Candlestick: Bullish Engulfing on 2024-12-17
110
+ Support: $193.16 (27 touches), $156.63 (26 touches) Resistance: $201.32 (4 touches)
111
+ ```
112
+
113
+ With extras (`pip install "narrata[all]"`):
114
+
115
+ ```text
116
+ AAPL (252 pts, business-daily): ▁▂▁▂▂▃▃▃▄▄▄▅▆▆▆▆▇▇▇█
117
+ Date range: 2024-01-02 to 2024-12-18
118
+ Range: [$140.61, $201.32] Mean: $170.44 Std: $17.52
119
+ Start: $141.05 End: $201.32 Change: +42.73%
120
+ Regime: Uptrend since 2024-10-02 (low volatility)
121
+ RSI(14): 72.9 (overbought) MACD: bullish crossover 7 days ago
122
+ BB: above upper band
123
+ SMA 50/200: golden cross
124
+ Volume: 0.95x 20-day avg (average)
125
+ Volatility: 1st percentile (extremely low)
126
+ SAX(16): aaabbbcddefggghh
127
+ Patterns: Ascending triangle forming since 2024-09-26
128
+ Candlestick: Doji on 2024-12-11
129
+ Support: $193.16 (27 touches), $156.63 (26 touches) Resistance: $201.32 (4 touches)
130
+ ```
131
+
132
+ ## Public API imports
133
+
134
+ ```python
135
+ from narrata import (
136
+ narrate,
137
+ analyze_summary,
138
+ analyze_regime,
139
+ analyze_indicators,
140
+ sax_encode,
141
+ astride_encode,
142
+ detect_patterns,
143
+ find_support_resistance,
144
+ make_sparkline,
145
+ digit_tokenize,
146
+ to_plain,
147
+ to_markdown_kv,
148
+ to_toon,
149
+ )
150
+ ```
151
+
152
+ ## FAQ
153
+
154
+ ### Is narrata redundant if I already use OpenBB, yfinance, or another data SDK?
155
+
156
+ No. `narrata` is complementary. It sits on top of your data access layer and converts OHLCV data into concise, LLM-ready narrative text.
157
+
158
+ ### Does narrata call an LLM or provide LLM endpoints?
159
+
160
+ No. `narrata` is a pure Python library with deterministic, programmatic analysis and narration. It does not call LLM APIs.
161
+
162
+ ## Citation
163
+
164
+ If you use `narrata` in research or public projects, cite this package using `CITATION.cff`.
@@ -0,0 +1,137 @@
1
+ # narrata
2
+
3
+ `narrata` turns OHLCV price series into compact, deterministic text summaries optimized for LLM context.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install narrata
9
+ ```
10
+
11
+ Install optional backends:
12
+
13
+ ```bash
14
+ pip install "narrata[all]"
15
+ ```
16
+
17
+ Requires Python 3.11+ and pandas 2.0+.
18
+
19
+ ## Quickstart
20
+
21
+ ```python
22
+ import numpy as np
23
+ import pandas as pd
24
+
25
+ from narrata import narrate
26
+
27
+ n = 120
28
+ dates = pd.date_range("2025-01-01", periods=n, freq="D")
29
+ rng = np.random.default_rng(7)
30
+ close = np.linspace(140.0, 175.0, n) + rng.normal(0.0, 1.0, n)
31
+ open_ = close + rng.normal(0.0, 0.6, n)
32
+ high = np.maximum(open_, close) + np.abs(rng.normal(0.7, 0.2, n))
33
+ low = np.minimum(open_, close) - np.abs(rng.normal(0.7, 0.2, n))
34
+ volume = rng.integers(900_000, 2_100_000, n)
35
+
36
+ df = pd.DataFrame(
37
+ {"Open": open_, "High": high, "Low": low, "Close": close, "Volume": volume},
38
+ index=dates,
39
+ )
40
+ df.attrs["ticker"] = "AAPL"
41
+
42
+ print(narrate(df))
43
+ ```
44
+
45
+ Example output:
46
+
47
+ ```text
48
+ AAPL (120 pts, daily): ▁▁▂▂▂▃▃▄▄▄▄▅▆▆▆▆▇▇██
49
+ Date range: 2025-01-01 to 2025-04-30
50
+ Range: [$139.99, $175.68] Mean: $157.35 Std: $10.33
51
+ Start: $140.00 End: $175.19 Change: +25.14%
52
+ Regime: Uptrend since 2025-01-02 (low volatility)
53
+ RSI(14): 65.1 (neutral-bullish) MACD: bullish crossover 1 day ago
54
+ BB: near upper band
55
+ Volume: 0.98x 20-day avg (average)
56
+ Volatility: 23rd percentile (low)
57
+ SAX(16): aaabbccdeeffgggh
58
+ Patterns: Ascending triangle forming since 2025-03-02
59
+ Candlestick: Doji on 2025-04-29
60
+ Support: $145.13 (13 touches), $139.99 (6 touches) Resistance: $175.68 (3 touches)
61
+ ```
62
+
63
+ ## Fallback vs extras (same input)
64
+
65
+ Using the same deterministic 252-point dataset:
66
+
67
+ Fallback-only (`pip install narrata`):
68
+
69
+ ```text
70
+ AAPL (252 pts, business-daily): ▁▂▁▂▂▃▃▃▄▄▄▅▆▆▆▆▇▇▇█
71
+ Date range: 2024-01-02 to 2024-12-18
72
+ Range: [$140.61, $201.32] Mean: $170.44 Std: $17.52
73
+ Start: $141.05 End: $201.32 Change: +42.73%
74
+ Regime: Uptrend since 2024-12-10 (low volatility)
75
+ RSI(14): 72.9 (overbought) MACD: bullish crossover 7 days ago
76
+ BB: above upper band
77
+ SMA 50/200: golden cross
78
+ Volume: 0.95x 20-day avg (average)
79
+ Volatility: 1st percentile (extremely low)
80
+ SAX(16): aaabbcdeefggghhh
81
+ Patterns: Ascending triangle forming since 2024-09-26
82
+ Candlestick: Bullish Engulfing on 2024-12-17
83
+ Support: $193.16 (27 touches), $156.63 (26 touches) Resistance: $201.32 (4 touches)
84
+ ```
85
+
86
+ With extras (`pip install "narrata[all]"`):
87
+
88
+ ```text
89
+ AAPL (252 pts, business-daily): ▁▂▁▂▂▃▃▃▄▄▄▅▆▆▆▆▇▇▇█
90
+ Date range: 2024-01-02 to 2024-12-18
91
+ Range: [$140.61, $201.32] Mean: $170.44 Std: $17.52
92
+ Start: $141.05 End: $201.32 Change: +42.73%
93
+ Regime: Uptrend since 2024-10-02 (low volatility)
94
+ RSI(14): 72.9 (overbought) MACD: bullish crossover 7 days ago
95
+ BB: above upper band
96
+ SMA 50/200: golden cross
97
+ Volume: 0.95x 20-day avg (average)
98
+ Volatility: 1st percentile (extremely low)
99
+ SAX(16): aaabbbcddefggghh
100
+ Patterns: Ascending triangle forming since 2024-09-26
101
+ Candlestick: Doji on 2024-12-11
102
+ Support: $193.16 (27 touches), $156.63 (26 touches) Resistance: $201.32 (4 touches)
103
+ ```
104
+
105
+ ## Public API imports
106
+
107
+ ```python
108
+ from narrata import (
109
+ narrate,
110
+ analyze_summary,
111
+ analyze_regime,
112
+ analyze_indicators,
113
+ sax_encode,
114
+ astride_encode,
115
+ detect_patterns,
116
+ find_support_resistance,
117
+ make_sparkline,
118
+ digit_tokenize,
119
+ to_plain,
120
+ to_markdown_kv,
121
+ to_toon,
122
+ )
123
+ ```
124
+
125
+ ## FAQ
126
+
127
+ ### Is narrata redundant if I already use OpenBB, yfinance, or another data SDK?
128
+
129
+ No. `narrata` is complementary. It sits on top of your data access layer and converts OHLCV data into concise, LLM-ready narrative text.
130
+
131
+ ### Does narrata call an LLM or provide LLM endpoints?
132
+
133
+ No. `narrata` is a pure Python library with deterministic, programmatic analysis and narration. It does not call LLM APIs.
134
+
135
+ ## Citation
136
+
137
+ If you use `narrata` in research or public projects, cite this package using `CITATION.cff`.
@@ -0,0 +1,90 @@
1
+ """Public API for narrata."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ from narrata.analysis.indicators import (
6
+ analyze_indicators,
7
+ compute_bollinger,
8
+ compute_ma_crossover,
9
+ compute_macd,
10
+ compute_rsi,
11
+ compute_volatility_percentile,
12
+ compute_volume_state,
13
+ describe_indicators,
14
+ )
15
+ from narrata.analysis.patterns import (
16
+ describe_candlestick,
17
+ describe_patterns,
18
+ detect_candlestick_pattern,
19
+ detect_chart_pattern,
20
+ detect_patterns,
21
+ )
22
+ from narrata.analysis.regimes import analyze_regime, describe_regime
23
+ from narrata.analysis.summary import analyze_summary, describe_summary
24
+ from narrata.analysis.support_resistance import describe_support_resistance, find_support_resistance
25
+ from narrata.analysis.symbolic import astride_encode, describe_astride, describe_sax, sax_encode
26
+ from narrata.composition.narrate import narrate
27
+ from narrata.compression.digits import digit_tokenize
28
+ from narrata.exceptions import NarrataError, UnsupportedFormatError, ValidationError
29
+ from narrata.formatting.serializers import format_sections, to_markdown_kv, to_plain, to_toon
30
+ from narrata.rendering.sparkline import make_sparkline
31
+ from narrata.types import (
32
+ IndicatorStats,
33
+ LevelStats,
34
+ OutputFormat,
35
+ PatternStats,
36
+ PriceLevel,
37
+ RegimeStats,
38
+ SummaryStats,
39
+ SymbolicStats,
40
+ )
41
+ from narrata.validation.ohlcv import infer_frequency_label, validate_ohlcv_frame
42
+
43
+ __version__ = version("narrata")
44
+
45
+ __all__ = [
46
+ "IndicatorStats",
47
+ "LevelStats",
48
+ "NarrataError",
49
+ "OutputFormat",
50
+ "PatternStats",
51
+ "PriceLevel",
52
+ "RegimeStats",
53
+ "SummaryStats",
54
+ "SymbolicStats",
55
+ "UnsupportedFormatError",
56
+ "ValidationError",
57
+ "astride_encode",
58
+ "analyze_indicators",
59
+ "analyze_regime",
60
+ "__version__",
61
+ "analyze_summary",
62
+ "compute_bollinger",
63
+ "compute_ma_crossover",
64
+ "compute_macd",
65
+ "compute_rsi",
66
+ "compute_volatility_percentile",
67
+ "compute_volume_state",
68
+ "describe_astride",
69
+ "describe_candlestick",
70
+ "describe_indicators",
71
+ "describe_patterns",
72
+ "describe_regime",
73
+ "describe_sax",
74
+ "describe_summary",
75
+ "describe_support_resistance",
76
+ "detect_candlestick_pattern",
77
+ "detect_chart_pattern",
78
+ "detect_patterns",
79
+ "digit_tokenize",
80
+ "format_sections",
81
+ "find_support_resistance",
82
+ "infer_frequency_label",
83
+ "make_sparkline",
84
+ "narrate",
85
+ "sax_encode",
86
+ "to_markdown_kv",
87
+ "to_plain",
88
+ "to_toon",
89
+ "validate_ohlcv_frame",
90
+ ]
@@ -0,0 +1,49 @@
1
+ """Numerical analysis primitives for narrata."""
2
+
3
+ from narrata.analysis.indicators import (
4
+ analyze_indicators,
5
+ compute_bollinger,
6
+ compute_ma_crossover,
7
+ compute_macd,
8
+ compute_rsi,
9
+ compute_volatility_percentile,
10
+ compute_volume_state,
11
+ describe_indicators,
12
+ )
13
+ from narrata.analysis.patterns import (
14
+ describe_candlestick,
15
+ describe_patterns,
16
+ detect_candlestick_pattern,
17
+ detect_chart_pattern,
18
+ detect_patterns,
19
+ )
20
+ from narrata.analysis.regimes import analyze_regime, describe_regime
21
+ from narrata.analysis.summary import analyze_summary, describe_summary
22
+ from narrata.analysis.support_resistance import describe_support_resistance, find_support_resistance
23
+ from narrata.analysis.symbolic import astride_encode, describe_astride, describe_sax, sax_encode
24
+
25
+ __all__ = [
26
+ "astride_encode",
27
+ "analyze_indicators",
28
+ "analyze_regime",
29
+ "analyze_summary",
30
+ "compute_bollinger",
31
+ "compute_ma_crossover",
32
+ "compute_macd",
33
+ "compute_rsi",
34
+ "compute_volatility_percentile",
35
+ "compute_volume_state",
36
+ "describe_astride",
37
+ "describe_candlestick",
38
+ "describe_indicators",
39
+ "describe_patterns",
40
+ "describe_regime",
41
+ "describe_sax",
42
+ "describe_summary",
43
+ "describe_support_resistance",
44
+ "detect_candlestick_pattern",
45
+ "detect_chart_pattern",
46
+ "detect_patterns",
47
+ "find_support_resistance",
48
+ "sax_encode",
49
+ ]