TradeChart 2.4.0__tar.gz → 2.5.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 (40) hide show
  1. {tradechart-2.4.0 → tradechart-2.5.0}/PKG-INFO +20 -16
  2. {tradechart-2.4.0 → tradechart-2.5.0}/README.md +18 -14
  3. {tradechart-2.4.0 → tradechart-2.5.0}/TradeChart.egg-info/PKG-INFO +20 -16
  4. {tradechart-2.4.0 → tradechart-2.5.0}/pyproject.toml +2 -2
  5. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/__init__.py +7 -1
  6. tradechart-2.5.0/tradechart/charts/__init__.py +11 -0
  7. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/charts/heatmap.py +41 -34
  8. tradechart-2.5.0/tradechart/charts/renderer.py +933 -0
  9. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/charts/themes.py +32 -24
  10. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/charts/watermark.py +10 -5
  11. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/config/settings.py +60 -0
  12. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/core/engine.py +45 -47
  13. tradechart-2.4.0/tradechart/charts/__init__.py +0 -8
  14. tradechart-2.4.0/tradechart/charts/renderer.py +0 -460
  15. {tradechart-2.4.0 → tradechart-2.5.0}/LICENSE +0 -0
  16. {tradechart-2.4.0 → tradechart-2.5.0}/TradeChart.egg-info/SOURCES.txt +0 -0
  17. {tradechart-2.4.0 → tradechart-2.5.0}/TradeChart.egg-info/dependency_links.txt +0 -0
  18. {tradechart-2.4.0 → tradechart-2.5.0}/TradeChart.egg-info/requires.txt +0 -0
  19. {tradechart-2.4.0 → tradechart-2.5.0}/TradeChart.egg-info/top_level.txt +0 -0
  20. {tradechart-2.4.0 → tradechart-2.5.0}/setup.cfg +0 -0
  21. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/charts/indicators.py +0 -0
  22. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/config/__init__.py +0 -0
  23. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/config/logger.py +0 -0
  24. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/core/__init__.py +0 -0
  25. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/data/__init__.py +0 -0
  26. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/data/fetcher.py +0 -0
  27. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/data/groups.py +0 -0
  28. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/data/models.py +0 -0
  29. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/data/provider_base.py +0 -0
  30. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/data/store.py +0 -0
  31. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/providers/__init__.py +0 -0
  32. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/providers/stooq_provider.py +0 -0
  33. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/providers/tradingview_provider.py +0 -0
  34. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/providers/yfinance_provider.py +0 -0
  35. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/utils/__init__.py +0 -0
  36. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/utils/exceptions.py +0 -0
  37. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/utils/formatting.py +0 -0
  38. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/utils/install.py +0 -0
  39. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart/utils/validation.py +0 -0
  40. {tradechart-2.4.0 → tradechart-2.5.0}/tradechart_examples/discord_demo_bot/discord_bot.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TradeChart
3
- Version: 2.4.0
4
- Summary: Production-quality financial chart generator — candlestick, line, area, OHLC, Heikin-Ashi, performance heatmaps, and sector group charts.
3
+ Version: 2.5.0
4
+ Summary: Sleek financial charts from Python — candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmaps.
5
5
  Author-email: "TRADELY.DEV" <dev@tradely.dev>
6
6
  License: Apache-2.0
7
7
  Project-URL: Homepage, https://github.com/techareaone/TradeChart
@@ -45,7 +45,7 @@ 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.4.0
48
+ # TradeChart — Library Edition v2.5.0
49
49
 
50
50
  **Python → Financial Charts**
51
51
  Generate production-quality candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmap charts from code.
@@ -64,7 +64,7 @@ pip install TradeChart
64
64
  | Extra | Installs | Benefit |
65
65
  |---|---|---|
66
66
  | `TradeChart[tradingview]` | `tvDatafeed` | TradingView as a fallback data provider |
67
- | `TradeChart[mplfinance]` | `mplfinance` | Higher-quality candlestick rendering |
67
+ | `TradeChart[mplfinance]` | `mplfinance` | Optional candlestick backend. The default engine is native. Opt in with `tc.config(engine="mplfinance")`. |
68
68
  | `TradeChart[xlsx]` | `openpyxl` | Excel `.xlsx` export support |
69
69
  | `TradeChart[all]` | All of the above | Everything |
70
70
 
@@ -453,6 +453,8 @@ tc.config(
453
453
  | `dpi` | `int` | `100` | `50`–`600` | Output resolution in dots per inch. Higher values produce larger, sharper files. |
454
454
  | `fig_size` | `tuple[int, int]` | `(12, 6)` | Any valid `(width, height)` in inches | Matplotlib figure size. Increase for wide monitors or presentations. |
455
455
  | `cache_ttl` | `int` | `300` | Any positive integer (seconds) | How long fetched data is kept in memory. `0` effectively disables caching. |
456
+ | `engine` | `str` | `"native"` | `"native"`, `"mplfinance"` | Drawing entry point. `"native"` is the default sleek engine. `"mplfinance"` keeps the optional candlestick backend for `"candle"` and `"heikin_ashi"`. |
457
+ | `font` | `str` | `"sans"` | `"sans"`, `"serif"`, `"mono"` | Typeface. `"sans"` is sans-serif and is used when this is omitted. `"serif"` and `"mono"` are the other built-in choices. |
456
458
 
457
459
  ---
458
460
 
@@ -486,9 +488,9 @@ tc.theme("classic")
486
488
 
487
489
  | Name | Background | Candle colours | Spine |
488
490
  |---|---|---|---|
489
- | `"dark"` | `#1e1e2f` (dark navy) | Green `#26a69a` / Red `#ef5350` | Hidden |
490
- | `"light"` | `#ffffff` (white) | Green `#26a69a` / Red `#ef5350` | Hidden |
491
- | `"classic"` | `#f5f5dc` (parchment) | Dark green `#2e7d32` / Dark red `#c62828` | Visible |
491
+ | `"dark"` | `#0e1117` | Green `#3dd68c` / Red `#f07178` | Hidden |
492
+ | `"light"` | `#f4f6f8` | Green `#1a9f6b` / Red `#e24b4b` | Hidden |
493
+ | `"classic"` | `#f3efe2` (parchment) | Green `#1f7a3a` / Red `#a32020` | Visible |
492
494
 
493
495
  ---
494
496
 
@@ -598,11 +600,19 @@ The global settings singleton and engine initialisation are protected by locks.
598
600
  **Heikin-Ashi**
599
601
  The `"heikin_ashi"` chart type converts standard OHLC data to Heikin-Ashi candles during rendering only. The cached source data and any DataFrame returned by `tc.data()` are never modified.
600
602
 
601
- **mplfinance**
602
- When `mplfinance` is installed (`pip install TradeChart[mplfinance]`), candlestick and Heikin-Ashi charts use it for higher-quality rendering. Otherwise a pure-matplotlib fallback is used automatically — no configuration required.
603
+ **Rendering**
604
+ `tc.chart()`, `tc.compare()`, and `tc.heatmap()` draw through the native engine (`render_chart`, `render_comparison`, and the heatmap renderer). Candles are two vector collections — one for wicks, one for bodies — the figure is positioned once, and the file is written in a single pass. That is lighter than a general-purpose chart stack, and it is the look in the examples below.
605
+
606
+ `mplfinance` is still supported. Install `TradeChart[mplfinance]` and select it when you want that backend for candlestick and Heikin-Ashi charts:
607
+
608
+ ```python
609
+ tc.config(engine="mplfinance")
610
+ ```
611
+
612
+ Line, area, OHLC, comparison, and heatmap charts stay on the native engine. Required dependencies are unchanged: `matplotlib`, `pandas`, `numpy`, and `yfinance`. `tvDatafeed`, `mplfinance`, and `openpyxl` remain optional extras.
603
613
 
604
614
  **Output resolution**
605
- Default DPI is 100, producing a ~1200 × 600 px image at the default figure size — well under 300 KB for all supported formats. Increase with `tc.config(dpi=200)` for sharper output, or `tc.config(dpi=300)` for print quality.
615
+ Default DPI is 100, producing a ~1200 × 600 px image at the default figure size. Increase with `tc.config(dpi=200)` for sharper output, or `tc.config(dpi=300)` for print quality.
606
616
 
607
617
  ---
608
618
 
@@ -632,12 +642,6 @@ except RenderError as e:
632
642
 
633
643
  ---
634
644
 
635
- ## Example Charts
636
- <img width="2081" height="1039" alt="image" src="https://github.com/user-attachments/assets/b93f79e6-a135-4de8-993d-ee13071fe791" />
637
- <img width="2081" height="1039" alt="image" src="https://github.com/user-attachments/assets/b0755b35-b21c-4b27-8faa-c57e13892dad" />
638
-
639
- ---
640
-
641
645
  ## Further Details
642
646
 
643
647
  - Documentation: [doc.tradely.dev](https://doc.tradely.dev)
@@ -1,4 +1,4 @@
1
- # TradeChart — Library Edition v2.4.0
1
+ # TradeChart — Library Edition v2.5.0
2
2
 
3
3
  **Python → Financial Charts**
4
4
  Generate production-quality candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmap charts from code.
@@ -17,7 +17,7 @@ pip install TradeChart
17
17
  | Extra | Installs | Benefit |
18
18
  |---|---|---|
19
19
  | `TradeChart[tradingview]` | `tvDatafeed` | TradingView as a fallback data provider |
20
- | `TradeChart[mplfinance]` | `mplfinance` | Higher-quality candlestick rendering |
20
+ | `TradeChart[mplfinance]` | `mplfinance` | Optional candlestick backend. The default engine is native. Opt in with `tc.config(engine="mplfinance")`. |
21
21
  | `TradeChart[xlsx]` | `openpyxl` | Excel `.xlsx` export support |
22
22
  | `TradeChart[all]` | All of the above | Everything |
23
23
 
@@ -406,6 +406,8 @@ tc.config(
406
406
  | `dpi` | `int` | `100` | `50`–`600` | Output resolution in dots per inch. Higher values produce larger, sharper files. |
407
407
  | `fig_size` | `tuple[int, int]` | `(12, 6)` | Any valid `(width, height)` in inches | Matplotlib figure size. Increase for wide monitors or presentations. |
408
408
  | `cache_ttl` | `int` | `300` | Any positive integer (seconds) | How long fetched data is kept in memory. `0` effectively disables caching. |
409
+ | `engine` | `str` | `"native"` | `"native"`, `"mplfinance"` | Drawing entry point. `"native"` is the default sleek engine. `"mplfinance"` keeps the optional candlestick backend for `"candle"` and `"heikin_ashi"`. |
410
+ | `font` | `str` | `"sans"` | `"sans"`, `"serif"`, `"mono"` | Typeface. `"sans"` is sans-serif and is used when this is omitted. `"serif"` and `"mono"` are the other built-in choices. |
409
411
 
410
412
  ---
411
413
 
@@ -439,9 +441,9 @@ tc.theme("classic")
439
441
 
440
442
  | Name | Background | Candle colours | Spine |
441
443
  |---|---|---|---|
442
- | `"dark"` | `#1e1e2f` (dark navy) | Green `#26a69a` / Red `#ef5350` | Hidden |
443
- | `"light"` | `#ffffff` (white) | Green `#26a69a` / Red `#ef5350` | Hidden |
444
- | `"classic"` | `#f5f5dc` (parchment) | Dark green `#2e7d32` / Dark red `#c62828` | Visible |
444
+ | `"dark"` | `#0e1117` | Green `#3dd68c` / Red `#f07178` | Hidden |
445
+ | `"light"` | `#f4f6f8` | Green `#1a9f6b` / Red `#e24b4b` | Hidden |
446
+ | `"classic"` | `#f3efe2` (parchment) | Green `#1f7a3a` / Red `#a32020` | Visible |
445
447
 
446
448
  ---
447
449
 
@@ -551,11 +553,19 @@ The global settings singleton and engine initialisation are protected by locks.
551
553
  **Heikin-Ashi**
552
554
  The `"heikin_ashi"` chart type converts standard OHLC data to Heikin-Ashi candles during rendering only. The cached source data and any DataFrame returned by `tc.data()` are never modified.
553
555
 
554
- **mplfinance**
555
- When `mplfinance` is installed (`pip install TradeChart[mplfinance]`), candlestick and Heikin-Ashi charts use it for higher-quality rendering. Otherwise a pure-matplotlib fallback is used automatically — no configuration required.
556
+ **Rendering**
557
+ `tc.chart()`, `tc.compare()`, and `tc.heatmap()` draw through the native engine (`render_chart`, `render_comparison`, and the heatmap renderer). Candles are two vector collections — one for wicks, one for bodies — the figure is positioned once, and the file is written in a single pass. That is lighter than a general-purpose chart stack, and it is the look in the examples below.
558
+
559
+ `mplfinance` is still supported. Install `TradeChart[mplfinance]` and select it when you want that backend for candlestick and Heikin-Ashi charts:
560
+
561
+ ```python
562
+ tc.config(engine="mplfinance")
563
+ ```
564
+
565
+ Line, area, OHLC, comparison, and heatmap charts stay on the native engine. Required dependencies are unchanged: `matplotlib`, `pandas`, `numpy`, and `yfinance`. `tvDatafeed`, `mplfinance`, and `openpyxl` remain optional extras.
556
566
 
557
567
  **Output resolution**
558
- Default DPI is 100, producing a ~1200 × 600 px image at the default figure size — well under 300 KB for all supported formats. Increase with `tc.config(dpi=200)` for sharper output, or `tc.config(dpi=300)` for print quality.
568
+ Default DPI is 100, producing a ~1200 × 600 px image at the default figure size. Increase with `tc.config(dpi=200)` for sharper output, or `tc.config(dpi=300)` for print quality.
559
569
 
560
570
  ---
561
571
 
@@ -585,12 +595,6 @@ except RenderError as e:
585
595
 
586
596
  ---
587
597
 
588
- ## Example Charts
589
- <img width="2081" height="1039" alt="image" src="https://github.com/user-attachments/assets/b93f79e6-a135-4de8-993d-ee13071fe791" />
590
- <img width="2081" height="1039" alt="image" src="https://github.com/user-attachments/assets/b0755b35-b21c-4b27-8faa-c57e13892dad" />
591
-
592
- ---
593
-
594
598
  ## Further Details
595
599
 
596
600
  - Documentation: [doc.tradely.dev](https://doc.tradely.dev)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TradeChart
3
- Version: 2.4.0
4
- Summary: Production-quality financial chart generator — candlestick, line, area, OHLC, Heikin-Ashi, performance heatmaps, and sector group charts.
3
+ Version: 2.5.0
4
+ Summary: Sleek financial charts from Python — candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmaps.
5
5
  Author-email: "TRADELY.DEV" <dev@tradely.dev>
6
6
  License: Apache-2.0
7
7
  Project-URL: Homepage, https://github.com/techareaone/TradeChart
@@ -45,7 +45,7 @@ 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.4.0
48
+ # TradeChart — Library Edition v2.5.0
49
49
 
50
50
  **Python → Financial Charts**
51
51
  Generate production-quality candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmap charts from code.
@@ -64,7 +64,7 @@ pip install TradeChart
64
64
  | Extra | Installs | Benefit |
65
65
  |---|---|---|
66
66
  | `TradeChart[tradingview]` | `tvDatafeed` | TradingView as a fallback data provider |
67
- | `TradeChart[mplfinance]` | `mplfinance` | Higher-quality candlestick rendering |
67
+ | `TradeChart[mplfinance]` | `mplfinance` | Optional candlestick backend. The default engine is native. Opt in with `tc.config(engine="mplfinance")`. |
68
68
  | `TradeChart[xlsx]` | `openpyxl` | Excel `.xlsx` export support |
69
69
  | `TradeChart[all]` | All of the above | Everything |
70
70
 
@@ -453,6 +453,8 @@ tc.config(
453
453
  | `dpi` | `int` | `100` | `50`–`600` | Output resolution in dots per inch. Higher values produce larger, sharper files. |
454
454
  | `fig_size` | `tuple[int, int]` | `(12, 6)` | Any valid `(width, height)` in inches | Matplotlib figure size. Increase for wide monitors or presentations. |
455
455
  | `cache_ttl` | `int` | `300` | Any positive integer (seconds) | How long fetched data is kept in memory. `0` effectively disables caching. |
456
+ | `engine` | `str` | `"native"` | `"native"`, `"mplfinance"` | Drawing entry point. `"native"` is the default sleek engine. `"mplfinance"` keeps the optional candlestick backend for `"candle"` and `"heikin_ashi"`. |
457
+ | `font` | `str` | `"sans"` | `"sans"`, `"serif"`, `"mono"` | Typeface. `"sans"` is sans-serif and is used when this is omitted. `"serif"` and `"mono"` are the other built-in choices. |
456
458
 
457
459
  ---
458
460
 
@@ -486,9 +488,9 @@ tc.theme("classic")
486
488
 
487
489
  | Name | Background | Candle colours | Spine |
488
490
  |---|---|---|---|
489
- | `"dark"` | `#1e1e2f` (dark navy) | Green `#26a69a` / Red `#ef5350` | Hidden |
490
- | `"light"` | `#ffffff` (white) | Green `#26a69a` / Red `#ef5350` | Hidden |
491
- | `"classic"` | `#f5f5dc` (parchment) | Dark green `#2e7d32` / Dark red `#c62828` | Visible |
491
+ | `"dark"` | `#0e1117` | Green `#3dd68c` / Red `#f07178` | Hidden |
492
+ | `"light"` | `#f4f6f8` | Green `#1a9f6b` / Red `#e24b4b` | Hidden |
493
+ | `"classic"` | `#f3efe2` (parchment) | Green `#1f7a3a` / Red `#a32020` | Visible |
492
494
 
493
495
  ---
494
496
 
@@ -598,11 +600,19 @@ The global settings singleton and engine initialisation are protected by locks.
598
600
  **Heikin-Ashi**
599
601
  The `"heikin_ashi"` chart type converts standard OHLC data to Heikin-Ashi candles during rendering only. The cached source data and any DataFrame returned by `tc.data()` are never modified.
600
602
 
601
- **mplfinance**
602
- When `mplfinance` is installed (`pip install TradeChart[mplfinance]`), candlestick and Heikin-Ashi charts use it for higher-quality rendering. Otherwise a pure-matplotlib fallback is used automatically — no configuration required.
603
+ **Rendering**
604
+ `tc.chart()`, `tc.compare()`, and `tc.heatmap()` draw through the native engine (`render_chart`, `render_comparison`, and the heatmap renderer). Candles are two vector collections — one for wicks, one for bodies — the figure is positioned once, and the file is written in a single pass. That is lighter than a general-purpose chart stack, and it is the look in the examples below.
605
+
606
+ `mplfinance` is still supported. Install `TradeChart[mplfinance]` and select it when you want that backend for candlestick and Heikin-Ashi charts:
607
+
608
+ ```python
609
+ tc.config(engine="mplfinance")
610
+ ```
611
+
612
+ Line, area, OHLC, comparison, and heatmap charts stay on the native engine. Required dependencies are unchanged: `matplotlib`, `pandas`, `numpy`, and `yfinance`. `tvDatafeed`, `mplfinance`, and `openpyxl` remain optional extras.
603
613
 
604
614
  **Output resolution**
605
- Default DPI is 100, producing a ~1200 × 600 px image at the default figure size — well under 300 KB for all supported formats. Increase with `tc.config(dpi=200)` for sharper output, or `tc.config(dpi=300)` for print quality.
615
+ Default DPI is 100, producing a ~1200 × 600 px image at the default figure size. Increase with `tc.config(dpi=200)` for sharper output, or `tc.config(dpi=300)` for print quality.
606
616
 
607
617
  ---
608
618
 
@@ -632,12 +642,6 @@ except RenderError as e:
632
642
 
633
643
  ---
634
644
 
635
- ## Example Charts
636
- <img width="2081" height="1039" alt="image" src="https://github.com/user-attachments/assets/b93f79e6-a135-4de8-993d-ee13071fe791" />
637
- <img width="2081" height="1039" alt="image" src="https://github.com/user-attachments/assets/b0755b35-b21c-4b27-8faa-c57e13892dad" />
638
-
639
- ---
640
-
641
645
  ## Further Details
642
646
 
643
647
  - Documentation: [doc.tradely.dev](https://doc.tradely.dev)
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "TradeChart"
7
- version = "2.4.0"
8
- description = "Production-quality financial chart generator — candlestick, line, area, OHLC, Heikin-Ashi, performance heatmaps, and sector group charts."
7
+ version = "2.5.0"
8
+ description = "Sleek financial charts from Python — candlestick, line, area, OHLC, Heikin-Ashi, and performance heatmaps."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
11
11
  requires-python = ">=3.10"
@@ -87,7 +87,7 @@ from tradechart.utils.exceptions import (
87
87
  )
88
88
  from tradechart.utils.validation import VALID_DURATIONS
89
89
 
90
- __version__ = "2.4.0"
90
+ __version__ = "2.5.0"
91
91
  __all__ = [
92
92
  "terminal", "theme", "watermark", "config",
93
93
  "chart", "compare", "heatmap", "data", "export", "clear_cache",
@@ -153,6 +153,8 @@ def config(**kwargs) -> dict:
153
153
  dpi : int — output resolution (50–600)
154
154
  fig_size : tuple[int,int] — figure dimensions in inches
155
155
  cache_ttl : int — data cache time-to-live in seconds
156
+ engine : str — ``"native"`` (default) or ``"mplfinance"``
157
+ font : str — ``"sans"`` (default), ``"serif"``, or ``"mono"``
156
158
 
157
159
  Example
158
160
  -------
@@ -167,6 +169,8 @@ def config(**kwargs) -> dict:
167
169
  "dpi": lambda v: setattr(s, "dpi", v),
168
170
  "fig_size": lambda v: setattr(s, "fig_size", v),
169
171
  "cache_ttl": lambda v: setattr(s, "cache_ttl", v),
172
+ "engine": lambda v: setattr(s, "chart_engine", v),
173
+ "font": lambda v: setattr(s, "font", v),
170
174
  }
171
175
  for key, value in kwargs.items():
172
176
  setter = dispatch.get(key)
@@ -185,6 +189,8 @@ def config(**kwargs) -> dict:
185
189
  "dpi": s.dpi,
186
190
  "fig_size": s.fig_size,
187
191
  "cache_ttl": s.cache_ttl,
192
+ "engine": s.chart_engine,
193
+ "font": s.font,
188
194
  }
189
195
 
190
196
 
@@ -0,0 +1,11 @@
1
+ """Chart rendering layer."""
2
+
3
+ from tradechart.charts.renderer import ChartRenderer, render_chart, render_comparison
4
+ from tradechart.charts.watermark import stamp_logo, clear_cache as clear_logo_cache
5
+ from tradechart.charts.themes import Theme, get_theme
6
+ from tradechart.charts.indicators import apply_indicators
7
+
8
+ __all__ = [
9
+ "ChartRenderer", "render_chart", "render_comparison",
10
+ "stamp_logo", "clear_logo_cache", "Theme", "get_theme", "apply_indicators",
11
+ ]
@@ -21,6 +21,7 @@ import matplotlib.patches as mpatches
21
21
 
22
22
  from tradechart.config.logger import get_logger
23
23
  from tradechart.config.settings import get_settings
24
+ from tradechart.charts.renderer import _draw_header, save_figure
24
25
  from tradechart.charts.themes import get_theme
25
26
  from tradechart.charts.watermark import stamp_logo
26
27
  from tradechart.utils.exceptions import RenderError
@@ -29,7 +30,7 @@ from tradechart.utils.exceptions import RenderError
29
30
  # The canvas spans [0, fig_aspect] × [0, 1], and since fig_aspect = fw/fh the
30
31
  # x and y data units are identical in physical size (both = fh inches/unit).
31
32
  # A single constant therefore produces visually uniform gaps on all four sides.
32
- _TILE_GAP = 0.006
33
+ _TILE_GAP = 0.008
33
34
 
34
35
 
35
36
  # ── Colour map: deep-red → slate-neutral → deep-green ───────────────────────
@@ -37,13 +38,11 @@ _TILE_GAP = 0.006
37
38
  _HEATMAP_CMAP = mcolors.LinearSegmentedColormap.from_list(
38
39
  "tradechart_heatmap",
39
40
  [
40
- "#8b1a1a", # deep red (large loss)
41
- "#c62828",
42
- "#ef5350", # light red
43
- "#546e7a", # slate-grey (near zero)
44
- "#26a69a", # teal-green
45
- "#00897b",
46
- "#004d40", # deep green (large gain)
41
+ "#8f2430",
42
+ "#f07178",
43
+ "#3a4454",
44
+ "#3dd68c",
45
+ "#147a4d",
47
46
  ],
48
47
  N=256,
49
48
  )
@@ -238,9 +237,10 @@ class HeatmapRenderer:
238
237
  log.detail("Heatmap layout: %s (%d tiles)", weight_note, len(layout))
239
238
 
240
239
  # ── Figure ───────────────────────────────────────────────────────────
241
- fig, ax = plt.subplots(figsize=(fw, fh))
240
+ fig, ax = plt.subplots(figsize=(fw, fh), dpi=settings.dpi)
242
241
  fig.patch.set_facecolor(theme.bg_color)
243
242
  ax.set_facecolor(theme.bg_color)
243
+ fig.subplots_adjust(left=0.055, right=0.915, top=0.80, bottom=0.14)
244
244
  ax.set_xlim(0, fig_aspect)
245
245
  ax.set_ylim(0, 1.0)
246
246
  ax.set_aspect("auto")
@@ -254,13 +254,18 @@ class HeatmapRenderer:
254
254
  price = prices.get(ticker)
255
255
  color = _tile_color(pct, vrange)
256
256
 
257
- rect = mpatches.Rectangle(
257
+ tile_w = (tx1 - tx0) - 2 * _TILE_GAP
258
+ tile_h = (ty1 - ty0) - 2 * _TILE_GAP
259
+ radius = min(0.012, tile_w * 0.08, tile_h * 0.08)
260
+ rect = mpatches.FancyBboxPatch(
258
261
  (tx0 + _TILE_GAP, ty0 + _TILE_GAP),
259
- (tx1 - tx0) - 2 * _TILE_GAP,
260
- (ty1 - ty0) - 2 * _TILE_GAP,
262
+ tile_w,
263
+ tile_h,
264
+ boxstyle=f"round,pad=0,rounding_size={radius:.4f}",
261
265
  facecolor=color,
262
266
  edgecolor="none",
263
267
  linewidth=0,
268
+ mutation_aspect=1,
264
269
  zorder=2,
265
270
  )
266
271
  ax.add_patch(rect)
@@ -294,17 +299,20 @@ class HeatmapRenderer:
294
299
  ty_t = cy
295
300
  ty_p = ty_pr = None
296
301
 
302
+ label_face, figure_face = settings.font_faces()
297
303
  ax.text(cx, ty_t, ticker,
298
304
  ha="center", va="center",
299
305
  fontsize=fs_ticker, fontweight="bold",
300
- color="white", zorder=3, clip_on=True)
306
+ color="white", zorder=3, clip_on=True,
307
+ fontfamily=label_face)
301
308
 
302
309
  if show_pct and ty_p is not None:
303
310
  sign = "+" if pct >= 0 else ""
304
311
  ax.text(cx, ty_p, f"{sign}{pct:.2f}%",
305
312
  ha="center", va="center",
306
313
  fontsize=fs_pct, color="white", alpha=0.92,
307
- zorder=3, clip_on=True)
314
+ zorder=3, clip_on=True,
315
+ fontfamily=figure_face)
308
316
 
309
317
  if show_price and ty_pr is not None:
310
318
  price_str = (
@@ -315,13 +323,15 @@ class HeatmapRenderer:
315
323
  ax.text(cx, ty_pr, price_str,
316
324
  ha="center", va="center",
317
325
  fontsize=fs_price, color="white", alpha=0.72,
318
- zorder=3, clip_on=True)
326
+ zorder=3, clip_on=True,
327
+ fontfamily=figure_face)
319
328
 
320
329
  # ── Title ─────────────────────────────────────────────────────────────
321
- subtitle = f"market-cap weighted" if has_caps else "equal weight"
322
- ax.set_title(
323
- f"{label} • {duration} • Performance Heatmap ({subtitle})",
324
- color=theme.text_color, fontsize=12, fontweight="bold", pad=12,
330
+ weight_note = "market-cap weighted" if has_caps else "equal weight"
331
+ _draw_header(
332
+ fig, theme,
333
+ title=label,
334
+ subtitle=f"{duration} · performance · {weight_note}",
325
335
  )
326
336
 
327
337
  # ── Colour-bar legend ──────────────────────────────────────────────────
@@ -334,26 +344,23 @@ class HeatmapRenderer:
334
344
  sm, ax=ax, orientation="horizontal",
335
345
  fraction=0.025, pad=0.03, aspect=50,
336
346
  )
337
- cbar.set_label("% Change", color=theme.text_color, fontsize=9)
338
- cbar.ax.tick_params(colors=theme.text_color, labelsize=8)
339
- for spine in cbar.ax.spines.values():
340
- spine.set_visible(False)
341
-
342
- fig.tight_layout(pad=1.5)
347
+ cbar.set_label("% change", color=theme.muted_color, fontsize=8)
348
+ _label_face, figure_face = settings.font_faces()
349
+ try:
350
+ cbar.ax.tick_params(
351
+ colors=theme.muted_color, labelsize=8, length=0, labelfontfamily=figure_face,
352
+ )
353
+ except TypeError:
354
+ cbar.ax.tick_params(colors=theme.muted_color, labelsize=8, length=0)
355
+ cbar.ax.xaxis.label.set_fontfamily(figure_face)
356
+ cbar.outline.set_visible(False)
343
357
 
344
358
  if settings.watermark_enabled:
345
359
  stamp_logo(fig, provider=provider)
346
360
 
347
361
  out_file = output_path.with_suffix(f".{fmt}")
348
- pil_kwargs: dict = {}
349
- if fmt == "png":
350
- pil_kwargs = {"compress_level": 6, "optimize": True}
351
- elif fmt in ("jpg", "jpeg", "webp"):
352
- pil_kwargs = {"quality": 82, "optimize": True}
353
- save_kwargs: dict = {"dpi": settings.dpi, "facecolor": fig.get_facecolor(), "bbox_inches": "tight"}
354
- if pil_kwargs:
355
- save_kwargs["pil_kwargs"] = pil_kwargs
356
- fig.savefig(out_file, **save_kwargs)
362
+ with plt.rc_context({"svg.fonttype": "none", "savefig.bbox": None}):
363
+ save_figure(fig, out_file, fmt, settings.dpi)
357
364
  plt.close(fig)
358
365
  log.detail("Saved heatmap → %s", out_file)
359
366
  return out_file