TradeChart 2.1.2__tar.gz → 2.2.1__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 (39) hide show
  1. {tradechart-2.1.2 → tradechart-2.2.1}/PKG-INFO +110 -12
  2. {tradechart-2.1.2 → tradechart-2.2.1}/README.md +109 -11
  3. {tradechart-2.1.2 → tradechart-2.2.1}/TradeChart.egg-info/PKG-INFO +110 -12
  4. {tradechart-2.1.2 → tradechart-2.2.1}/TradeChart.egg-info/SOURCES.txt +1 -0
  5. {tradechart-2.1.2 → tradechart-2.2.1}/pyproject.toml +1 -1
  6. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/__init__.py +166 -3
  7. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/config/settings.py +20 -1
  8. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/data/fetcher.py +65 -9
  9. tradechart-2.2.1/tradechart/data/store.py +131 -0
  10. tradechart-2.2.1/tradechart_examples/discord_demo_bot/discord_bot.py +998 -0
  11. tradechart-2.1.2/tradechart_examples/discord_demo_bot/discord_bot.py +0 -665
  12. {tradechart-2.1.2 → tradechart-2.2.1}/LICENSE +0 -0
  13. {tradechart-2.1.2 → tradechart-2.2.1}/TradeChart.egg-info/dependency_links.txt +0 -0
  14. {tradechart-2.1.2 → tradechart-2.2.1}/TradeChart.egg-info/requires.txt +0 -0
  15. {tradechart-2.1.2 → tradechart-2.2.1}/TradeChart.egg-info/top_level.txt +0 -0
  16. {tradechart-2.1.2 → tradechart-2.2.1}/setup.cfg +0 -0
  17. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/charts/__init__.py +0 -0
  18. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/charts/heatmap.py +0 -0
  19. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/charts/indicators.py +0 -0
  20. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/charts/renderer.py +0 -0
  21. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/charts/themes.py +0 -0
  22. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/charts/watermark.py +0 -0
  23. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/config/__init__.py +0 -0
  24. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/config/logger.py +0 -0
  25. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/core/__init__.py +0 -0
  26. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/core/engine.py +0 -0
  27. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/data/__init__.py +0 -0
  28. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/data/groups.py +0 -0
  29. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/data/models.py +0 -0
  30. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/data/provider_base.py +0 -0
  31. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/providers/__init__.py +0 -0
  32. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/providers/stooq_provider.py +0 -0
  33. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/providers/tradingview_provider.py +0 -0
  34. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/providers/yfinance_provider.py +0 -0
  35. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/utils/__init__.py +0 -0
  36. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/utils/exceptions.py +0 -0
  37. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/utils/formatting.py +0 -0
  38. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/utils/install.py +0 -0
  39. {tradechart-2.1.2 → tradechart-2.2.1}/tradechart/utils/validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TradeChart
3
- Version: 2.1.2
3
+ Version: 2.2.1
4
4
  Summary: Production-quality financial chart generator — candlestick, line, area, OHLC, Heikin-Ashi, performance heatmaps, and sector group charts.
5
5
  Author-email: "TRADELY.DEV" <dev@tradely.dev>
6
6
  License: Apache-2.0
@@ -45,11 +45,11 @@ Requires-Dist: build>=1.0; extra == "dev"
45
45
  Requires-Dist: twine>=5.0; extra == "dev"
46
46
  Dynamic: license-file
47
47
 
48
- # TradeChart — Library Edition v2.1.2
48
+ # TradeChart — Library Edition v2.2.1
49
49
 
50
50
  **Python → Financial Charts**
51
51
  Generate production-quality candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmap charts from code.
52
- Automatic multi-provider data fetching · 7 technical indicators · 3 themes · PNG/SVG/PDF output · 14 built-in sector groups.
52
+ Automatic multi-provider data fetching · persistent disk store · 7 technical indicators · 3 themes · PNG/SVG/PDF output · 14 built-in sector groups.
53
53
 
54
54
  ---
55
55
 
@@ -84,6 +84,93 @@ tc.chart("AAPL", "1mo", "candle", indicators=["sma", "bollinger"])
84
84
 
85
85
  ---
86
86
 
87
+ ## Persistent Data Store
88
+
89
+ `tc.store()` adds a two-level cache on top of the existing in-memory TTL cache: data fetched from any provider is written to a `tradechart_FetchData/` folder and reloaded automatically in future sessions, eliminating redundant network requests.
90
+
91
+ ### Set the store location
92
+
93
+ Call `tc.store()` once with a filesystem path. The folder `tradechart_FetchData/` is created there automatically.
94
+
95
+ ```python
96
+ import tradechart as tc
97
+
98
+ tc.store("/data/myproject") # absolute path
99
+ tc.store(".") # current working directory
100
+ tc.store("~/market_data") # tilde expansion supported
101
+ ```
102
+
103
+ ### Pre-fetch tickers and groups
104
+
105
+ After setting the path, call `tc.store()` again on subsequent lines listing any combination of individual ticker symbols, named sector group keys, or plain lists. An optional duration string as the last argument controls the fetch window (defaults to `"1mo"`).
106
+
107
+ ```python
108
+ tc.store("AAPL") # single ticker, default duration (1mo)
109
+ tc.store("AAPL", "MSFT", "NVDA", "3mo") # three tickers for 3 months
110
+ tc.store("mag7", "6mo") # named group — fetches all 7 tickers
111
+ tc.store("tech", "finance", "1y") # two named groups for 1 year
112
+ tc.store(tc.SECTOR_GROUPS["crypto"], "3mo") # list passed directly
113
+ ```
114
+
115
+ Any valid `SECTOR_GROUPS` key (`"mag7"`, `"tech"`, `"finance"`, `"energy"`, …) is expanded to its full ticker list automatically.
116
+
117
+ ### How it works
118
+
119
+ Once a store path is configured, every call to `chart()`, `data()`, `export()`, `compare()`, or `heatmap()` uses a three-level lookup before touching the network:
120
+
121
+ 1. **In-memory cache** — sub-millisecond, TTL-based (existing behaviour).
122
+ 2. **Disk store (fresh)** — if the stored file is younger than the bar-resolution threshold, it is served as-is. No network call.
123
+ 3. **Disk store (stale) + live fetch** — if the stored file is older than the threshold, the library fetches the current window from a live provider to get the missing bars, then **merges** those new rows on top of the stored history. Historical bars are never discarded or re-requested. The merged result is written back to disk and served.
124
+
125
+ The staleness threshold matches the resolution of the data so charts are never more than one bar behind:
126
+
127
+ | Duration | Bar resolution | Refreshes after |
128
+ |---|---|---|
129
+ | `"1d"`, `"5d"` | 5 / 15-min bars | 4 hours |
130
+ | `"1mo"`, `"3mo"`, `"6mo"` | Daily bars | 24 hours |
131
+ | `"1y"`, `"2y"`, `"5y"` | Weekly bars | 7 days |
132
+ | `"10y"`, `"max"` | Monthly bars | 30 days |
133
+
134
+ ```python
135
+ tc.store("/data/myproject")
136
+ tc.store("AAPL", "MSFT", "mag7", "3mo") # fetch once, write to disk
137
+
138
+ # Later — same session or a completely new one:
139
+ tc.chart("AAPL", "3mo") # served from disk, no network call
140
+ tc.data("MSFT", "3mo") # same
141
+
142
+ # After 24 hours (daily bars): only the new day's bar is fetched and merged
143
+ # in — the months of stored history are kept and reused as-is
144
+ tc.chart("AAPL", "3mo") # delta fetch + merge, then cached
145
+ ```
146
+
147
+ ### Clearing stored data
148
+
149
+ ```python
150
+ tc.clear_cache() # flush in-memory cache only (default)
151
+ tc.clear_cache(disk=True) # also delete all CSV files in tradechart_FetchData/
152
+ ```
153
+
154
+ ### Store folder layout
155
+
156
+ ```
157
+ /data/myproject/
158
+ └── tradechart_FetchData/
159
+ ├── AAPL_3mo.csv
160
+ ├── MSFT_3mo.csv
161
+ ├── NVDA_3mo.csv
162
+ └── ...
163
+ ```
164
+
165
+ | Parameter | Type | Description |
166
+ |---|---|---|
167
+ | `*args` | `str \| list \| tuple` | A single path string **or** any mix of ticker symbols, named sector group keys, and/or lists — optionally ending with a duration string. |
168
+ | `duration` | `str` (keyword) | Fallback duration when none is provided in `*args`. Default `"1mo"`. |
169
+
170
+ **Returns:** the `tradechart_FetchData/` `Path` when setting the store; `None` when pre-fetching.
171
+
172
+ ---
173
+
87
174
  ## Ticker Groups — Averaged Series
88
175
 
89
176
  `tc.chart()`, `tc.data()`, and `tc.export()` accept a **list or tuple of ticker symbols** in addition to a single string. When a group is supplied the library:
@@ -137,12 +224,14 @@ If one or more tickers in the group fail to fetch data, they are **skipped with
137
224
  | `tc.theme(name)` | Set chart colour theme |
138
225
  | `tc.watermark(enabled)` | Toggle the TRADELY logo watermark |
139
226
  | `tc.config(**kwargs)` | Batch-set multiple global options at once |
227
+ | `tc.store(path)` | Set persistent data-store directory |
228
+ | `tc.store(ticker, ...)` | Pre-fetch and persist tickers / groups |
140
229
  | `tc.chart(...)` | Fetch data and render a chart image |
141
230
  | `tc.compare(...)` | Overlay multiple tickers on one chart |
142
231
  | `tc.heatmap(...)` | Render a performance heatmap for a ticker group |
143
232
  | `tc.data(...)` | Fetch raw OHLCV data as a DataFrame |
144
233
  | `tc.export(...)` | Export market data to CSV / JSON / XLSX |
145
- | `tc.clear_cache()` | Flush the in-memory data cache |
234
+ | `tc.clear_cache(disk=False)` | Flush in-memory cache; optionally wipe disk store |
146
235
  | `tc.SECTOR_GROUPS` | Dict of 14 pre-defined ticker lists (sectors, indices, crypto, …) |
147
236
 
148
237
  ---
@@ -252,7 +341,7 @@ Tile sizes use a **squarified treemap** algorithm to minimise wasted space while
252
341
 
253
342
  ## `tc.SECTOR_GROUPS` — Pre-defined Ticker Lists
254
343
 
255
- A dictionary of curated ticker groups ready to pass into `tc.heatmap()`, `tc.compare()`, `tc.chart()`, or `tc.export()`.
344
+ A dictionary of curated ticker groups ready to pass into `tc.heatmap()`, `tc.compare()`, `tc.chart()`, `tc.store()`, or `tc.export()`.
256
345
 
257
346
  ```python
258
347
  import tradechart as tc
@@ -417,10 +506,15 @@ The TRADELY logo is stamped in the bottom-left corner of every chart by default.
417
506
  ## `tc.clear_cache()` — Flush Data Cache
418
507
 
419
508
  ```python
420
- tc.clear_cache()
509
+ tc.clear_cache() # flush in-memory cache only
510
+ tc.clear_cache(disk=True) # also wipe all CSVs in tradechart_FetchData/
421
511
  ```
422
512
 
423
- Clears all in-memory cached market data, forcing the next fetch to go to the network. Useful after a TTL has not yet expired but you need fresh data (e.g. during live market hours).
513
+ | Parameter | Type | Default | Description |
514
+ |---|---|---|---|
515
+ | `disk` | `bool` | `False` | When `True`, deletes all CSV files in the disk store (the folder is kept). Has no effect if no store path has been set. |
516
+
517
+ Clears in-memory cached market data, forcing the next fetch to check the disk store (or go to the network if no store is configured). Useful during live market hours when TTL has not yet expired but you need a fresh quote.
424
518
 
425
519
  ---
426
520
 
@@ -475,18 +569,22 @@ TradeChart tries providers in priority order and falls back automatically on fai
475
569
 
476
570
  | Priority | Provider | Requires | Notes |
477
571
  |---|---|---|---|
478
- | 1 | **yfinance** | Included by default | Primary source. Covers stocks, ETFs, indices, crypto, forex. |
572
+ | 0 | **Disk store** | `tc.store(path)` called once | Served from local CSV when fresh. When stale, only the missing bars are fetched from a live provider and merged on top — historical rows are never re-requested. |
573
+ | 1 | **yfinance** | Included by default | Primary live source. Covers stocks, ETFs, indices, crypto, forex. |
479
574
  | 2 | **TradingView** | `pip install TradeChart[tradingview]` | Tried if yfinance returns empty or fails. Attempts multiple exchanges automatically (`NASDAQ`, `NYSE`, `AMEX`, `CRYPTO`, `FX`). |
480
575
  | 3 | **Stooq** | Nothing — free CSV endpoint | Final fallback. No API key required. Duration mapped to a rolling date range. |
481
576
 
482
- If all three providers fail, a `DataFetchError` is raised with a list of each provider's error message.
577
+ If all live providers fail and no disk data exists, a `DataFetchError` is raised with a list of each provider's error message.
483
578
 
484
579
  ---
485
580
 
486
581
  ## Notes
487
582
 
488
- **Caching**
489
- Fetched data is cached in-memory for `cache_ttl` seconds (default 300 s / 5 minutes). All subsequent calls with the same ticker and duration within that window are served from cache. Call `tc.clear_cache()` to force a re-fetch, or set `tc.config(cache_ttl=0)` to disable caching entirely.
583
+ **Persistent disk store**
584
+ When `tc.store()` is configured, every successful live fetch is written to `tradechart_FetchData/` as a CSV file. On subsequent requests the library checks whether the stored data is fresh enough (based on bar resolution — 24 hours for daily bars, 4 hours for intraday, etc.). If fresh, it is served directly with no network call. If stale, only the most recent bars are fetched from a live provider and merged on top of the stored history — historical rows are never discarded or re-fetched. Use `tc.clear_cache(disk=True)` to wipe stored files and force a full re-fetch.
585
+
586
+ **In-memory caching**
587
+ Fetched data is also cached in-memory for `cache_ttl` seconds (default 300 s / 5 minutes). All subsequent calls with the same ticker and duration within that window are served from the memory cache. Call `tc.clear_cache()` to force re-evaluation (disk store is still checked before going to the network). Set `tc.config(cache_ttl=0)` to disable the memory cache entirely.
490
588
 
491
589
  **File collision handling**
492
590
  By default (`overwrite=False`), TradeChart appends a counter to avoid overwriting existing files: `chart.png` → `chart_1.png` → `chart_2.png`. Set `tc.config(overwrite=True)` to overwrite silently.
@@ -518,7 +616,7 @@ All TradeChart exceptions inherit from `TradeChartError`.
518
616
  | `InvalidTickerError` | The ticker string fails validation (too long, invalid characters) |
519
617
  | `RenderError` | Chart rendering fails (e.g. empty dataset after cleaning) |
520
618
  | `OutputError` | The chart cannot be saved (e.g. permission denied) |
521
- | `ConfigError` | An unknown key is passed to `tc.config()` |
619
+ | `ConfigError` | An unknown key is passed to `tc.config()`, or `tc.store()` is called with tickers before a path is set |
522
620
 
523
621
  ```python
524
622
  import tradechart as tc
@@ -1,8 +1,8 @@
1
- # TradeChart — Library Edition v2.1.2
1
+ # TradeChart — Library Edition v2.2.1
2
2
 
3
3
  **Python → Financial Charts**
4
4
  Generate production-quality candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmap charts from code.
5
- Automatic multi-provider data fetching · 7 technical indicators · 3 themes · PNG/SVG/PDF output · 14 built-in sector groups.
5
+ Automatic multi-provider data fetching · persistent disk store · 7 technical indicators · 3 themes · PNG/SVG/PDF output · 14 built-in sector groups.
6
6
 
7
7
  ---
8
8
 
@@ -37,6 +37,93 @@ tc.chart("AAPL", "1mo", "candle", indicators=["sma", "bollinger"])
37
37
 
38
38
  ---
39
39
 
40
+ ## Persistent Data Store
41
+
42
+ `tc.store()` adds a two-level cache on top of the existing in-memory TTL cache: data fetched from any provider is written to a `tradechart_FetchData/` folder and reloaded automatically in future sessions, eliminating redundant network requests.
43
+
44
+ ### Set the store location
45
+
46
+ Call `tc.store()` once with a filesystem path. The folder `tradechart_FetchData/` is created there automatically.
47
+
48
+ ```python
49
+ import tradechart as tc
50
+
51
+ tc.store("/data/myproject") # absolute path
52
+ tc.store(".") # current working directory
53
+ tc.store("~/market_data") # tilde expansion supported
54
+ ```
55
+
56
+ ### Pre-fetch tickers and groups
57
+
58
+ After setting the path, call `tc.store()` again on subsequent lines listing any combination of individual ticker symbols, named sector group keys, or plain lists. An optional duration string as the last argument controls the fetch window (defaults to `"1mo"`).
59
+
60
+ ```python
61
+ tc.store("AAPL") # single ticker, default duration (1mo)
62
+ tc.store("AAPL", "MSFT", "NVDA", "3mo") # three tickers for 3 months
63
+ tc.store("mag7", "6mo") # named group — fetches all 7 tickers
64
+ tc.store("tech", "finance", "1y") # two named groups for 1 year
65
+ tc.store(tc.SECTOR_GROUPS["crypto"], "3mo") # list passed directly
66
+ ```
67
+
68
+ Any valid `SECTOR_GROUPS` key (`"mag7"`, `"tech"`, `"finance"`, `"energy"`, …) is expanded to its full ticker list automatically.
69
+
70
+ ### How it works
71
+
72
+ Once a store path is configured, every call to `chart()`, `data()`, `export()`, `compare()`, or `heatmap()` uses a three-level lookup before touching the network:
73
+
74
+ 1. **In-memory cache** — sub-millisecond, TTL-based (existing behaviour).
75
+ 2. **Disk store (fresh)** — if the stored file is younger than the bar-resolution threshold, it is served as-is. No network call.
76
+ 3. **Disk store (stale) + live fetch** — if the stored file is older than the threshold, the library fetches the current window from a live provider to get the missing bars, then **merges** those new rows on top of the stored history. Historical bars are never discarded or re-requested. The merged result is written back to disk and served.
77
+
78
+ The staleness threshold matches the resolution of the data so charts are never more than one bar behind:
79
+
80
+ | Duration | Bar resolution | Refreshes after |
81
+ |---|---|---|
82
+ | `"1d"`, `"5d"` | 5 / 15-min bars | 4 hours |
83
+ | `"1mo"`, `"3mo"`, `"6mo"` | Daily bars | 24 hours |
84
+ | `"1y"`, `"2y"`, `"5y"` | Weekly bars | 7 days |
85
+ | `"10y"`, `"max"` | Monthly bars | 30 days |
86
+
87
+ ```python
88
+ tc.store("/data/myproject")
89
+ tc.store("AAPL", "MSFT", "mag7", "3mo") # fetch once, write to disk
90
+
91
+ # Later — same session or a completely new one:
92
+ tc.chart("AAPL", "3mo") # served from disk, no network call
93
+ tc.data("MSFT", "3mo") # same
94
+
95
+ # After 24 hours (daily bars): only the new day's bar is fetched and merged
96
+ # in — the months of stored history are kept and reused as-is
97
+ tc.chart("AAPL", "3mo") # delta fetch + merge, then cached
98
+ ```
99
+
100
+ ### Clearing stored data
101
+
102
+ ```python
103
+ tc.clear_cache() # flush in-memory cache only (default)
104
+ tc.clear_cache(disk=True) # also delete all CSV files in tradechart_FetchData/
105
+ ```
106
+
107
+ ### Store folder layout
108
+
109
+ ```
110
+ /data/myproject/
111
+ └── tradechart_FetchData/
112
+ ├── AAPL_3mo.csv
113
+ ├── MSFT_3mo.csv
114
+ ├── NVDA_3mo.csv
115
+ └── ...
116
+ ```
117
+
118
+ | Parameter | Type | Description |
119
+ |---|---|---|
120
+ | `*args` | `str \| list \| tuple` | A single path string **or** any mix of ticker symbols, named sector group keys, and/or lists — optionally ending with a duration string. |
121
+ | `duration` | `str` (keyword) | Fallback duration when none is provided in `*args`. Default `"1mo"`. |
122
+
123
+ **Returns:** the `tradechart_FetchData/` `Path` when setting the store; `None` when pre-fetching.
124
+
125
+ ---
126
+
40
127
  ## Ticker Groups — Averaged Series
41
128
 
42
129
  `tc.chart()`, `tc.data()`, and `tc.export()` accept a **list or tuple of ticker symbols** in addition to a single string. When a group is supplied the library:
@@ -90,12 +177,14 @@ If one or more tickers in the group fail to fetch data, they are **skipped with
90
177
  | `tc.theme(name)` | Set chart colour theme |
91
178
  | `tc.watermark(enabled)` | Toggle the TRADELY logo watermark |
92
179
  | `tc.config(**kwargs)` | Batch-set multiple global options at once |
180
+ | `tc.store(path)` | Set persistent data-store directory |
181
+ | `tc.store(ticker, ...)` | Pre-fetch and persist tickers / groups |
93
182
  | `tc.chart(...)` | Fetch data and render a chart image |
94
183
  | `tc.compare(...)` | Overlay multiple tickers on one chart |
95
184
  | `tc.heatmap(...)` | Render a performance heatmap for a ticker group |
96
185
  | `tc.data(...)` | Fetch raw OHLCV data as a DataFrame |
97
186
  | `tc.export(...)` | Export market data to CSV / JSON / XLSX |
98
- | `tc.clear_cache()` | Flush the in-memory data cache |
187
+ | `tc.clear_cache(disk=False)` | Flush in-memory cache; optionally wipe disk store |
99
188
  | `tc.SECTOR_GROUPS` | Dict of 14 pre-defined ticker lists (sectors, indices, crypto, …) |
100
189
 
101
190
  ---
@@ -205,7 +294,7 @@ Tile sizes use a **squarified treemap** algorithm to minimise wasted space while
205
294
 
206
295
  ## `tc.SECTOR_GROUPS` — Pre-defined Ticker Lists
207
296
 
208
- A dictionary of curated ticker groups ready to pass into `tc.heatmap()`, `tc.compare()`, `tc.chart()`, or `tc.export()`.
297
+ A dictionary of curated ticker groups ready to pass into `tc.heatmap()`, `tc.compare()`, `tc.chart()`, `tc.store()`, or `tc.export()`.
209
298
 
210
299
  ```python
211
300
  import tradechart as tc
@@ -370,10 +459,15 @@ The TRADELY logo is stamped in the bottom-left corner of every chart by default.
370
459
  ## `tc.clear_cache()` — Flush Data Cache
371
460
 
372
461
  ```python
373
- tc.clear_cache()
462
+ tc.clear_cache() # flush in-memory cache only
463
+ tc.clear_cache(disk=True) # also wipe all CSVs in tradechart_FetchData/
374
464
  ```
375
465
 
376
- Clears all in-memory cached market data, forcing the next fetch to go to the network. Useful after a TTL has not yet expired but you need fresh data (e.g. during live market hours).
466
+ | Parameter | Type | Default | Description |
467
+ |---|---|---|---|
468
+ | `disk` | `bool` | `False` | When `True`, deletes all CSV files in the disk store (the folder is kept). Has no effect if no store path has been set. |
469
+
470
+ Clears in-memory cached market data, forcing the next fetch to check the disk store (or go to the network if no store is configured). Useful during live market hours when TTL has not yet expired but you need a fresh quote.
377
471
 
378
472
  ---
379
473
 
@@ -428,18 +522,22 @@ TradeChart tries providers in priority order and falls back automatically on fai
428
522
 
429
523
  | Priority | Provider | Requires | Notes |
430
524
  |---|---|---|---|
431
- | 1 | **yfinance** | Included by default | Primary source. Covers stocks, ETFs, indices, crypto, forex. |
525
+ | 0 | **Disk store** | `tc.store(path)` called once | Served from local CSV when fresh. When stale, only the missing bars are fetched from a live provider and merged on top — historical rows are never re-requested. |
526
+ | 1 | **yfinance** | Included by default | Primary live source. Covers stocks, ETFs, indices, crypto, forex. |
432
527
  | 2 | **TradingView** | `pip install TradeChart[tradingview]` | Tried if yfinance returns empty or fails. Attempts multiple exchanges automatically (`NASDAQ`, `NYSE`, `AMEX`, `CRYPTO`, `FX`). |
433
528
  | 3 | **Stooq** | Nothing — free CSV endpoint | Final fallback. No API key required. Duration mapped to a rolling date range. |
434
529
 
435
- If all three providers fail, a `DataFetchError` is raised with a list of each provider's error message.
530
+ If all live providers fail and no disk data exists, a `DataFetchError` is raised with a list of each provider's error message.
436
531
 
437
532
  ---
438
533
 
439
534
  ## Notes
440
535
 
441
- **Caching**
442
- Fetched data is cached in-memory for `cache_ttl` seconds (default 300 s / 5 minutes). All subsequent calls with the same ticker and duration within that window are served from cache. Call `tc.clear_cache()` to force a re-fetch, or set `tc.config(cache_ttl=0)` to disable caching entirely.
536
+ **Persistent disk store**
537
+ When `tc.store()` is configured, every successful live fetch is written to `tradechart_FetchData/` as a CSV file. On subsequent requests the library checks whether the stored data is fresh enough (based on bar resolution — 24 hours for daily bars, 4 hours for intraday, etc.). If fresh, it is served directly with no network call. If stale, only the most recent bars are fetched from a live provider and merged on top of the stored history — historical rows are never discarded or re-fetched. Use `tc.clear_cache(disk=True)` to wipe stored files and force a full re-fetch.
538
+
539
+ **In-memory caching**
540
+ Fetched data is also cached in-memory for `cache_ttl` seconds (default 300 s / 5 minutes). All subsequent calls with the same ticker and duration within that window are served from the memory cache. Call `tc.clear_cache()` to force re-evaluation (disk store is still checked before going to the network). Set `tc.config(cache_ttl=0)` to disable the memory cache entirely.
443
541
 
444
542
  **File collision handling**
445
543
  By default (`overwrite=False`), TradeChart appends a counter to avoid overwriting existing files: `chart.png` → `chart_1.png` → `chart_2.png`. Set `tc.config(overwrite=True)` to overwrite silently.
@@ -471,7 +569,7 @@ All TradeChart exceptions inherit from `TradeChartError`.
471
569
  | `InvalidTickerError` | The ticker string fails validation (too long, invalid characters) |
472
570
  | `RenderError` | Chart rendering fails (e.g. empty dataset after cleaning) |
473
571
  | `OutputError` | The chart cannot be saved (e.g. permission denied) |
474
- | `ConfigError` | An unknown key is passed to `tc.config()` |
572
+ | `ConfigError` | An unknown key is passed to `tc.config()`, or `tc.store()` is called with tickers before a path is set |
475
573
 
476
574
  ```python
477
575
  import tradechart as tc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TradeChart
3
- Version: 2.1.2
3
+ Version: 2.2.1
4
4
  Summary: Production-quality financial chart generator — candlestick, line, area, OHLC, Heikin-Ashi, performance heatmaps, and sector group charts.
5
5
  Author-email: "TRADELY.DEV" <dev@tradely.dev>
6
6
  License: Apache-2.0
@@ -45,11 +45,11 @@ Requires-Dist: build>=1.0; extra == "dev"
45
45
  Requires-Dist: twine>=5.0; extra == "dev"
46
46
  Dynamic: license-file
47
47
 
48
- # TradeChart — Library Edition v2.1.2
48
+ # TradeChart — Library Edition v2.2.1
49
49
 
50
50
  **Python → Financial Charts**
51
51
  Generate production-quality candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmap charts from code.
52
- Automatic multi-provider data fetching · 7 technical indicators · 3 themes · PNG/SVG/PDF output · 14 built-in sector groups.
52
+ Automatic multi-provider data fetching · persistent disk store · 7 technical indicators · 3 themes · PNG/SVG/PDF output · 14 built-in sector groups.
53
53
 
54
54
  ---
55
55
 
@@ -84,6 +84,93 @@ tc.chart("AAPL", "1mo", "candle", indicators=["sma", "bollinger"])
84
84
 
85
85
  ---
86
86
 
87
+ ## Persistent Data Store
88
+
89
+ `tc.store()` adds a two-level cache on top of the existing in-memory TTL cache: data fetched from any provider is written to a `tradechart_FetchData/` folder and reloaded automatically in future sessions, eliminating redundant network requests.
90
+
91
+ ### Set the store location
92
+
93
+ Call `tc.store()` once with a filesystem path. The folder `tradechart_FetchData/` is created there automatically.
94
+
95
+ ```python
96
+ import tradechart as tc
97
+
98
+ tc.store("/data/myproject") # absolute path
99
+ tc.store(".") # current working directory
100
+ tc.store("~/market_data") # tilde expansion supported
101
+ ```
102
+
103
+ ### Pre-fetch tickers and groups
104
+
105
+ After setting the path, call `tc.store()` again on subsequent lines listing any combination of individual ticker symbols, named sector group keys, or plain lists. An optional duration string as the last argument controls the fetch window (defaults to `"1mo"`).
106
+
107
+ ```python
108
+ tc.store("AAPL") # single ticker, default duration (1mo)
109
+ tc.store("AAPL", "MSFT", "NVDA", "3mo") # three tickers for 3 months
110
+ tc.store("mag7", "6mo") # named group — fetches all 7 tickers
111
+ tc.store("tech", "finance", "1y") # two named groups for 1 year
112
+ tc.store(tc.SECTOR_GROUPS["crypto"], "3mo") # list passed directly
113
+ ```
114
+
115
+ Any valid `SECTOR_GROUPS` key (`"mag7"`, `"tech"`, `"finance"`, `"energy"`, …) is expanded to its full ticker list automatically.
116
+
117
+ ### How it works
118
+
119
+ Once a store path is configured, every call to `chart()`, `data()`, `export()`, `compare()`, or `heatmap()` uses a three-level lookup before touching the network:
120
+
121
+ 1. **In-memory cache** — sub-millisecond, TTL-based (existing behaviour).
122
+ 2. **Disk store (fresh)** — if the stored file is younger than the bar-resolution threshold, it is served as-is. No network call.
123
+ 3. **Disk store (stale) + live fetch** — if the stored file is older than the threshold, the library fetches the current window from a live provider to get the missing bars, then **merges** those new rows on top of the stored history. Historical bars are never discarded or re-requested. The merged result is written back to disk and served.
124
+
125
+ The staleness threshold matches the resolution of the data so charts are never more than one bar behind:
126
+
127
+ | Duration | Bar resolution | Refreshes after |
128
+ |---|---|---|
129
+ | `"1d"`, `"5d"` | 5 / 15-min bars | 4 hours |
130
+ | `"1mo"`, `"3mo"`, `"6mo"` | Daily bars | 24 hours |
131
+ | `"1y"`, `"2y"`, `"5y"` | Weekly bars | 7 days |
132
+ | `"10y"`, `"max"` | Monthly bars | 30 days |
133
+
134
+ ```python
135
+ tc.store("/data/myproject")
136
+ tc.store("AAPL", "MSFT", "mag7", "3mo") # fetch once, write to disk
137
+
138
+ # Later — same session or a completely new one:
139
+ tc.chart("AAPL", "3mo") # served from disk, no network call
140
+ tc.data("MSFT", "3mo") # same
141
+
142
+ # After 24 hours (daily bars): only the new day's bar is fetched and merged
143
+ # in — the months of stored history are kept and reused as-is
144
+ tc.chart("AAPL", "3mo") # delta fetch + merge, then cached
145
+ ```
146
+
147
+ ### Clearing stored data
148
+
149
+ ```python
150
+ tc.clear_cache() # flush in-memory cache only (default)
151
+ tc.clear_cache(disk=True) # also delete all CSV files in tradechart_FetchData/
152
+ ```
153
+
154
+ ### Store folder layout
155
+
156
+ ```
157
+ /data/myproject/
158
+ └── tradechart_FetchData/
159
+ ├── AAPL_3mo.csv
160
+ ├── MSFT_3mo.csv
161
+ ├── NVDA_3mo.csv
162
+ └── ...
163
+ ```
164
+
165
+ | Parameter | Type | Description |
166
+ |---|---|---|
167
+ | `*args` | `str \| list \| tuple` | A single path string **or** any mix of ticker symbols, named sector group keys, and/or lists — optionally ending with a duration string. |
168
+ | `duration` | `str` (keyword) | Fallback duration when none is provided in `*args`. Default `"1mo"`. |
169
+
170
+ **Returns:** the `tradechart_FetchData/` `Path` when setting the store; `None` when pre-fetching.
171
+
172
+ ---
173
+
87
174
  ## Ticker Groups — Averaged Series
88
175
 
89
176
  `tc.chart()`, `tc.data()`, and `tc.export()` accept a **list or tuple of ticker symbols** in addition to a single string. When a group is supplied the library:
@@ -137,12 +224,14 @@ If one or more tickers in the group fail to fetch data, they are **skipped with
137
224
  | `tc.theme(name)` | Set chart colour theme |
138
225
  | `tc.watermark(enabled)` | Toggle the TRADELY logo watermark |
139
226
  | `tc.config(**kwargs)` | Batch-set multiple global options at once |
227
+ | `tc.store(path)` | Set persistent data-store directory |
228
+ | `tc.store(ticker, ...)` | Pre-fetch and persist tickers / groups |
140
229
  | `tc.chart(...)` | Fetch data and render a chart image |
141
230
  | `tc.compare(...)` | Overlay multiple tickers on one chart |
142
231
  | `tc.heatmap(...)` | Render a performance heatmap for a ticker group |
143
232
  | `tc.data(...)` | Fetch raw OHLCV data as a DataFrame |
144
233
  | `tc.export(...)` | Export market data to CSV / JSON / XLSX |
145
- | `tc.clear_cache()` | Flush the in-memory data cache |
234
+ | `tc.clear_cache(disk=False)` | Flush in-memory cache; optionally wipe disk store |
146
235
  | `tc.SECTOR_GROUPS` | Dict of 14 pre-defined ticker lists (sectors, indices, crypto, …) |
147
236
 
148
237
  ---
@@ -252,7 +341,7 @@ Tile sizes use a **squarified treemap** algorithm to minimise wasted space while
252
341
 
253
342
  ## `tc.SECTOR_GROUPS` — Pre-defined Ticker Lists
254
343
 
255
- A dictionary of curated ticker groups ready to pass into `tc.heatmap()`, `tc.compare()`, `tc.chart()`, or `tc.export()`.
344
+ A dictionary of curated ticker groups ready to pass into `tc.heatmap()`, `tc.compare()`, `tc.chart()`, `tc.store()`, or `tc.export()`.
256
345
 
257
346
  ```python
258
347
  import tradechart as tc
@@ -417,10 +506,15 @@ The TRADELY logo is stamped in the bottom-left corner of every chart by default.
417
506
  ## `tc.clear_cache()` — Flush Data Cache
418
507
 
419
508
  ```python
420
- tc.clear_cache()
509
+ tc.clear_cache() # flush in-memory cache only
510
+ tc.clear_cache(disk=True) # also wipe all CSVs in tradechart_FetchData/
421
511
  ```
422
512
 
423
- Clears all in-memory cached market data, forcing the next fetch to go to the network. Useful after a TTL has not yet expired but you need fresh data (e.g. during live market hours).
513
+ | Parameter | Type | Default | Description |
514
+ |---|---|---|---|
515
+ | `disk` | `bool` | `False` | When `True`, deletes all CSV files in the disk store (the folder is kept). Has no effect if no store path has been set. |
516
+
517
+ Clears in-memory cached market data, forcing the next fetch to check the disk store (or go to the network if no store is configured). Useful during live market hours when TTL has not yet expired but you need a fresh quote.
424
518
 
425
519
  ---
426
520
 
@@ -475,18 +569,22 @@ TradeChart tries providers in priority order and falls back automatically on fai
475
569
 
476
570
  | Priority | Provider | Requires | Notes |
477
571
  |---|---|---|---|
478
- | 1 | **yfinance** | Included by default | Primary source. Covers stocks, ETFs, indices, crypto, forex. |
572
+ | 0 | **Disk store** | `tc.store(path)` called once | Served from local CSV when fresh. When stale, only the missing bars are fetched from a live provider and merged on top — historical rows are never re-requested. |
573
+ | 1 | **yfinance** | Included by default | Primary live source. Covers stocks, ETFs, indices, crypto, forex. |
479
574
  | 2 | **TradingView** | `pip install TradeChart[tradingview]` | Tried if yfinance returns empty or fails. Attempts multiple exchanges automatically (`NASDAQ`, `NYSE`, `AMEX`, `CRYPTO`, `FX`). |
480
575
  | 3 | **Stooq** | Nothing — free CSV endpoint | Final fallback. No API key required. Duration mapped to a rolling date range. |
481
576
 
482
- If all three providers fail, a `DataFetchError` is raised with a list of each provider's error message.
577
+ If all live providers fail and no disk data exists, a `DataFetchError` is raised with a list of each provider's error message.
483
578
 
484
579
  ---
485
580
 
486
581
  ## Notes
487
582
 
488
- **Caching**
489
- Fetched data is cached in-memory for `cache_ttl` seconds (default 300 s / 5 minutes). All subsequent calls with the same ticker and duration within that window are served from cache. Call `tc.clear_cache()` to force a re-fetch, or set `tc.config(cache_ttl=0)` to disable caching entirely.
583
+ **Persistent disk store**
584
+ When `tc.store()` is configured, every successful live fetch is written to `tradechart_FetchData/` as a CSV file. On subsequent requests the library checks whether the stored data is fresh enough (based on bar resolution — 24 hours for daily bars, 4 hours for intraday, etc.). If fresh, it is served directly with no network call. If stale, only the most recent bars are fetched from a live provider and merged on top of the stored history — historical rows are never discarded or re-fetched. Use `tc.clear_cache(disk=True)` to wipe stored files and force a full re-fetch.
585
+
586
+ **In-memory caching**
587
+ Fetched data is also cached in-memory for `cache_ttl` seconds (default 300 s / 5 minutes). All subsequent calls with the same ticker and duration within that window are served from the memory cache. Call `tc.clear_cache()` to force re-evaluation (disk store is still checked before going to the network). Set `tc.config(cache_ttl=0)` to disable the memory cache entirely.
490
588
 
491
589
  **File collision handling**
492
590
  By default (`overwrite=False`), TradeChart appends a counter to avoid overwriting existing files: `chart.png` → `chart_1.png` → `chart_2.png`. Set `tc.config(overwrite=True)` to overwrite silently.
@@ -518,7 +616,7 @@ All TradeChart exceptions inherit from `TradeChartError`.
518
616
  | `InvalidTickerError` | The ticker string fails validation (too long, invalid characters) |
519
617
  | `RenderError` | Chart rendering fails (e.g. empty dataset after cleaning) |
520
618
  | `OutputError` | The chart cannot be saved (e.g. permission denied) |
521
- | `ConfigError` | An unknown key is passed to `tc.config()` |
619
+ | `ConfigError` | An unknown key is passed to `tc.config()`, or `tc.store()` is called with tickers before a path is set |
522
620
 
523
621
  ```python
524
622
  import tradechart as tc
@@ -23,6 +23,7 @@ tradechart/data/fetcher.py
23
23
  tradechart/data/groups.py
24
24
  tradechart/data/models.py
25
25
  tradechart/data/provider_base.py
26
+ tradechart/data/store.py
26
27
  tradechart/providers/__init__.py
27
28
  tradechart/providers/stooq_provider.py
28
29
  tradechart/providers/tradingview_provider.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "TradeChart"
7
- version = "2.1.2"
7
+ version = "2.2.1"
8
8
  description = "Production-quality financial chart generator — candlestick, line, area, OHLC, Heikin-Ashi, performance heatmaps, and sector group charts."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}