seolpyo-mplchart 1.4.1__py3-none-any.whl → 2.1.0__py3-none-any.whl

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 (83) hide show
  1. seolpyo_mplchart/__init__.py +53 -333
  2. seolpyo_mplchart/_chart/__init__.py +145 -0
  3. seolpyo_mplchart/_chart/_base.py +217 -0
  4. seolpyo_mplchart/_chart/_cursor/__init__.py +2 -0
  5. seolpyo_mplchart/_chart/_cursor/_artist.py +217 -0
  6. seolpyo_mplchart/_chart/_cursor/_cursor.py +165 -0
  7. seolpyo_mplchart/_chart/_cursor/_info.py +187 -0
  8. seolpyo_mplchart/_chart/_draw/__init__.py +2 -0
  9. seolpyo_mplchart/_chart/_draw/_artist.py +50 -0
  10. seolpyo_mplchart/_chart/_draw/_data.py +314 -0
  11. seolpyo_mplchart/_chart/_draw/_draw.py +103 -0
  12. seolpyo_mplchart/_chart/_draw/_lim.py +265 -0
  13. seolpyo_mplchart/_chart/_slider/__init__.py +1 -0
  14. seolpyo_mplchart/_chart/_slider/_base.py +268 -0
  15. seolpyo_mplchart/_chart/_slider/_data.py +105 -0
  16. seolpyo_mplchart/_chart/_slider/_mouse.py +176 -0
  17. seolpyo_mplchart/_chart/_slider/_nav.py +204 -0
  18. seolpyo_mplchart/_chart/base/__init__.py +111 -0
  19. seolpyo_mplchart/_chart/base/a_canvas.py +250 -0
  20. seolpyo_mplchart/_chart/base/b_artist.py +143 -0
  21. seolpyo_mplchart/_chart/base/c_draw.py +100 -0
  22. seolpyo_mplchart/_chart/base/d_segment.py +262 -0
  23. seolpyo_mplchart/_chart/base/e_axis.py +267 -0
  24. seolpyo_mplchart/_chart/base/f_background.py +62 -0
  25. seolpyo_mplchart/_chart/base/g_event.py +66 -0
  26. seolpyo_mplchart/_chart/base/h_data.py +138 -0
  27. seolpyo_mplchart/_chart/base/test.py +58 -0
  28. seolpyo_mplchart/_chart/cursor/__init__.py +125 -0
  29. seolpyo_mplchart/_chart/cursor/b_artist.py +130 -0
  30. seolpyo_mplchart/_chart/cursor/c_draw.py +96 -0
  31. seolpyo_mplchart/_chart/cursor/d_segment.py +359 -0
  32. seolpyo_mplchart/_chart/cursor/e_axis.py +65 -0
  33. seolpyo_mplchart/_chart/cursor/g_event.py +233 -0
  34. seolpyo_mplchart/_chart/cursor/h_data.py +61 -0
  35. seolpyo_mplchart/_chart/cursor/test.py +69 -0
  36. seolpyo_mplchart/_chart/slider/__init__.py +169 -0
  37. seolpyo_mplchart/_chart/slider/a_canvas.py +260 -0
  38. seolpyo_mplchart/_chart/slider/b_artist.py +91 -0
  39. seolpyo_mplchart/_chart/slider/c_draw.py +54 -0
  40. seolpyo_mplchart/_chart/slider/d_segment.py +166 -0
  41. seolpyo_mplchart/_chart/slider/e_axis.py +70 -0
  42. seolpyo_mplchart/_chart/slider/f_background.py +37 -0
  43. seolpyo_mplchart/_chart/slider/g_event.py +353 -0
  44. seolpyo_mplchart/_chart/slider/h_data.py +102 -0
  45. seolpyo_mplchart/_chart/slider/test.py +71 -0
  46. seolpyo_mplchart/_chart/test.py +121 -0
  47. seolpyo_mplchart/_config/__init__.py +3 -0
  48. seolpyo_mplchart/_config/ax.py +28 -0
  49. seolpyo_mplchart/_config/candle.py +31 -0
  50. seolpyo_mplchart/_config/config.py +21 -0
  51. seolpyo_mplchart/_config/cursor.py +49 -0
  52. seolpyo_mplchart/_config/figure.py +40 -0
  53. seolpyo_mplchart/_config/format.py +51 -0
  54. seolpyo_mplchart/_config/ma.py +17 -0
  55. seolpyo_mplchart/_config/slider/__init__.py +2 -0
  56. seolpyo_mplchart/_config/slider/config.py +24 -0
  57. seolpyo_mplchart/_config/slider/figure.py +19 -0
  58. seolpyo_mplchart/_config/slider/nav.py +10 -0
  59. seolpyo_mplchart/_config/unit.py +19 -0
  60. seolpyo_mplchart/_config/utils.py +67 -0
  61. seolpyo_mplchart/_config/volume.py +27 -0
  62. seolpyo_mplchart/_cursor.py +27 -25
  63. seolpyo_mplchart/_draw.py +7 -18
  64. seolpyo_mplchart/_slider.py +26 -20
  65. seolpyo_mplchart/_utils/__init__.py +10 -0
  66. seolpyo_mplchart/_utils/nums.py +67 -0
  67. seolpyo_mplchart/_utils/theme/__init__.py +15 -0
  68. seolpyo_mplchart/_utils/theme/dark.py +57 -0
  69. seolpyo_mplchart/_utils/theme/light.py +56 -0
  70. seolpyo_mplchart/_utils/utils.py +28 -0
  71. seolpyo_mplchart/_utils/xl/__init__.py +15 -0
  72. seolpyo_mplchart/_utils/xl/csv.py +46 -0
  73. seolpyo_mplchart/_utils/xl/xlsx.py +49 -0
  74. seolpyo_mplchart/sample/apple.txt +6058 -0
  75. seolpyo_mplchart/sample/samsung.txt +5938 -0
  76. seolpyo_mplchart/test.py +172 -56
  77. seolpyo_mplchart/xl_to_dict.py +47 -0
  78. seolpyo_mplchart-2.1.0.dist-info/METADATA +718 -0
  79. seolpyo_mplchart-2.1.0.dist-info/RECORD +89 -0
  80. {seolpyo_mplchart-1.4.1.dist-info → seolpyo_mplchart-2.1.0.dist-info}/WHEEL +1 -1
  81. seolpyo_mplchart-1.4.1.dist-info/METADATA +0 -57
  82. seolpyo_mplchart-1.4.1.dist-info/RECORD +0 -17
  83. {seolpyo_mplchart-1.4.1.dist-info → seolpyo_mplchart-2.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,102 @@
1
+ from matplotlib.axes import Axes
2
+ from matplotlib.text import Text
3
+ import pandas as pd
4
+
5
+ from ..._config import ConfigData
6
+
7
+
8
+ class Base:
9
+ CONFIG: ConfigData
10
+ df: pd.DataFrame
11
+
12
+ key_date = 'date'
13
+ key_open, key_high, key_low, key_close = ('open', 'high', 'low', 'close')
14
+ key_volume = 'volume'
15
+
16
+ ax_slider: Axes
17
+
18
+ index_list: list[int] = []
19
+
20
+ artist_text_slider: Text
21
+
22
+ axis: callable
23
+ get_default_xlim: callable
24
+ set_variables: callable
25
+
26
+ _set_slider_collection: callable
27
+ vxmin: int
28
+ vxmax: int
29
+
30
+
31
+ class SliderMixin(Base):
32
+ min_distance = 5
33
+
34
+ def get_default_xlim(self):
35
+ xmax = self.index_list[-1] + 1
36
+ xmin = xmax - 120
37
+ if xmin < 0:
38
+ xmin = 0
39
+ return (xmin, xmax)
40
+
41
+ def set_variables(self):
42
+ super().set_variables()
43
+
44
+ self._set_slider()
45
+ return
46
+
47
+ def _set_slider(self):
48
+ # print('_set_slider')
49
+ self._set_slider_xtick()
50
+
51
+ xmax = self.index_list[-1]
52
+ # 슬라이더 xlim
53
+ xdistance = round(xmax / 30)
54
+ self.slider_xmin, self.slider_xmax = (-xdistance, xmax+xdistance)
55
+ self.ax_slider.set_xlim(self.slider_xmin, self.slider_xmax)
56
+
57
+ # 네비게이터 경계선 두께
58
+ self._nav_width = round((self.slider_xmax - self.slider_xmin) / 250, 2)
59
+
60
+ # 슬라이더 ylim
61
+ ymin, ymax = (self.df['low'].min(), self.df['high'].max())
62
+ ysub = ymax - ymin
63
+ ydistance = round(ysub / 5, self.CONFIG.UNIT.digit+2)
64
+ self.slider_ymin, self.slider_ymax = (ymin-ydistance, ymax+ydistance)
65
+ self.ax_slider.set_ylim(self.slider_ymin, self.slider_ymax)
66
+
67
+ self._set_slider_collection()
68
+ self._set_slider_text_position()
69
+
70
+ return
71
+
72
+ def _set_slider_text_position(self):
73
+ # 슬라이더 텍스트 y
74
+ self.artist_text_slider.set_y(self.df['high'].max())
75
+ return
76
+
77
+ def _set_slider_xtick(self):
78
+ indices = [0, self.index_list[-1]]
79
+ # print(f'{indices=}')
80
+
81
+ date_list = [self.df.iloc[idx]['date'] for idx in indices]
82
+ # print(f'{date_list=}')
83
+ # xtick 설정, major tick과 겹쳐서 무시되는 것 방지
84
+ self.ax_slider.set_xticks([idx+0.01 for idx in indices], labels=date_list, minor=True)
85
+
86
+ labels = self.ax_slider.get_xticklabels(minor=True)
87
+ # print(f'{labels=}')
88
+ for label, align in zip(labels, ['center', 'center']):
89
+ # 라벨 텍스트 정렬
90
+ label.set_horizontalalignment(align)
91
+ return
92
+
93
+
94
+ class DataMixin(SliderMixin):
95
+ min_distance = 5
96
+ _nav_width: float
97
+
98
+ slider_xmin: int
99
+ slider_xmax: int
100
+ slider_ymin: float
101
+ slider_ymax: float
102
+
@@ -0,0 +1,71 @@
1
+ import sys
2
+ from pathlib import Path
3
+ name_pkg = 'seolpyo_mplchart'
4
+ path_pkg = Path(__file__)
5
+ while path_pkg.name != name_pkg:
6
+ path_pkg = path_pkg.parent
7
+ sys.path = [path_pkg.parent.__str__()] + sys.path
8
+
9
+ import json
10
+
11
+ import pandas as pd
12
+ import matplotlib.pyplot as plt
13
+
14
+ from seolpyo_mplchart._utils.theme import set_theme
15
+ from seolpyo_mplchart._config import SLIDERCONFIG
16
+ from seolpyo_mplchart._chart.slider import Chart
17
+
18
+
19
+ path_file = path_pkg / 'sample' / 'samsung.txt'
20
+ with open(path_file, 'r', encoding='utf-8') as txt:
21
+ data = json.load(txt)
22
+ df = pd.DataFrame(data[:800])
23
+
24
+
25
+ class C(Chart):
26
+ limit_candle = 100
27
+ limit_wick = 300
28
+ limit_volume = 10
29
+ limit_ma = 200
30
+ t = 'light'
31
+ # watermark = ''
32
+ def __init__(self):
33
+ super().__init__()
34
+ # super().__init__(config=set_theme(SLIDERCONFIG, theme='dark'))
35
+ self.figure.canvas.mpl_connect('button_press_event', lambda x: self.theme(x))
36
+
37
+ def theme(self, e):
38
+ btn = getattr(e, 'button')
39
+ # print(f'{str(btn)=}')
40
+ if str(btn) == '3':
41
+ # print('refresh')
42
+ if self.t == 'light':
43
+ self.slider_top = True
44
+ self.t = 'dark'
45
+ # self.CONFIG.MA.linewidth = 1
46
+ self.get_candle_segment = lambda **x: Chart.get_candle_segment(self, **x)
47
+ self.CONFIG.CANDLE.linewidth = 0.8
48
+ else:
49
+ self.slider_top = False
50
+ self.t = 'light'
51
+ # self.CONFIG.MA.linewidth = 3
52
+ self.get_candle_segment = self.get_bar_segment
53
+ self.CONFIG.CANDLE.linewidth = 1.3
54
+ # print(f'{self.t=}')
55
+ self.CONFIG = set_theme(self.CONFIG, theme=self.t)
56
+ self.refresh()
57
+ return
58
+
59
+
60
+ def run():
61
+ chart = C()
62
+ chart.set_data(df)
63
+ plt.show()
64
+ plt.close()
65
+ return
66
+
67
+
68
+ if __name__ == '__main__':
69
+ run()
70
+
71
+
@@ -0,0 +1,121 @@
1
+ import sys
2
+ from pathlib import Path
3
+ name_pkg = 'seolpyo_mplchart'
4
+ path_pkg = Path(__file__)
5
+ while path_pkg.name != name_pkg:
6
+ path_pkg = path_pkg.parent
7
+ sys.path = [path_pkg.parent.__str__()] + sys.path
8
+
9
+ import json
10
+
11
+ import pandas as pd
12
+ import matplotlib.pyplot as plt
13
+
14
+
15
+ path_file = path_pkg / 'sample' / 'samsung.txt'
16
+ with open(path_file, 'r', encoding='utf-8') as txt:
17
+ data = json.load(txt)
18
+ df = pd.DataFrame(data[:100])
19
+
20
+ def test_base():
21
+ from seolpyo_mplchart._chart._base import Base
22
+ Base()
23
+ plt.show()
24
+ return
25
+
26
+ def test_draw():
27
+ from seolpyo_mplchart._chart._draw import Chart
28
+ c = Chart()
29
+ # c.CONFIG.CANDLE.FACECOLOR.bull_fall = 'y'
30
+ # c.CONFIG.CANDLE.EDGECOLOR.bull_fall = 'k'
31
+ # c.CONFIG.CANDLE.FACECOLOR.bear_rise = 'k'
32
+ # c.CONFIG.CANDLE.EDGECOLOR.bear_rise = 'pink'
33
+ # c.CONFIG.VOLUME.EDGECOLOR.rise = 'k'
34
+ # c.CONFIG.AX.facecolor = 'k'
35
+ # c.CONFIG.AX.TICK.edgecolor = 'yellow'
36
+ # c.CONFIG.AX.TICK.fontcolor = 'pink'
37
+ # c.set_color()
38
+ # c.volume = None
39
+ c.set_data(df)
40
+ plt.show()
41
+ return
42
+
43
+
44
+ def test_cursor():
45
+ from seolpyo_mplchart._chart._cursor._info import Chart
46
+ from seolpyo_mplchart._config import DEFAULTCONFIG_EN
47
+ c = Chart()
48
+ # c.CONFIG = DEFAULTCONFIG_EN
49
+ c.refresh()
50
+ c.fraction = True
51
+ c.set_data(df)
52
+ plt.show()
53
+ return
54
+
55
+ def test_slider():
56
+ from seolpyo_mplchart._chart._slider import Chart
57
+ c = Chart()
58
+ c.set_data(df)
59
+ plt.show()
60
+ return
61
+
62
+
63
+ if __name__ == '__main__':
64
+ # test_base()
65
+ # test_draw()
66
+ # test_cursor()
67
+ test_slider()
68
+
69
+
70
+ import seolpyo_mplchart as mc
71
+
72
+
73
+ # class Chart(mc.SliderChart):
74
+ # format_candleinfo = mc.format_candleinfo_ko + '\nCustom info: {ci}'
75
+ # format_volumeinfo = mc.format_volumeinfo_ko
76
+ # min_distance = 2
77
+
78
+ # def __init__(self, *args, **kwargs):
79
+ # super().__init__(*args, **kwargs)
80
+ # self.collection_candle.set_linewidth(1.5)
81
+ # return
82
+
83
+ # def get_info_kwargs(self, is_price, **kwargs):
84
+ # if is_price:
85
+ # kwargs['ci'] = 'You can add Custom text Info or Change text info.'
86
+ # kwargs['close'] = 'You can Change close price info.'
87
+ # return kwargs
88
+
89
+ # def get_candle_segment(self, *, x, left, right, top, bottom, is_up, high, low):
90
+ # if is_up:
91
+ # return (
92
+ # (x, top), (right, top), (x, top),
93
+ # (x, high),
94
+ # (x, low),
95
+ # (x, bottom), (left, bottom), (x, bottom),
96
+ # )
97
+ # else:
98
+ # return (
99
+ # (x, bottom), (right, bottom), (x, bottom),
100
+ # (x, high),
101
+ # (x, low),
102
+ # (x, top), (left, top), (x, top),
103
+ # )
104
+
105
+
106
+
107
+ # C = Chart()
108
+ # path_file = Path(__file__).parent / 'sample/samsung.txt'
109
+ # # C.format_candleinfo = mc.format_candleinfo_ko
110
+ # # C.format_volumeinfo = mc.format_volumeinfo_ko
111
+ # # C.volume = None
112
+
113
+
114
+ # with open(path_file, 'r', encoding='utf-8') as txt:
115
+ # data = json.load(txt)
116
+ # df = pd.DataFrame(data[:100])
117
+
118
+ # C.set_data(df)
119
+
120
+ # mc.show()
121
+ # mc.close()
@@ -0,0 +1,3 @@
1
+ from .config import DEFAULTCONFIG, DEFAULTCONFIG_EN, ConfigData
2
+ from .slider import SLIDERCONFIG, SLIDERCONFIG_EN, SliderConfigData
3
+
@@ -0,0 +1,28 @@
1
+
2
+
3
+ class Grid:
4
+ def __init__(self):
5
+ self.visible = True
6
+ self.linewidth = 0.7
7
+ self.color: str|tuple[float, float, float, float] = '#d0d0d0'
8
+ self.linestyle = '-'
9
+ self.dashes = (1, 0)
10
+ self.axis = 'both'
11
+
12
+ GRID = Grid()
13
+
14
+ class TickData:
15
+ def __init__(self):
16
+ self.edgecolor: str|tuple[float, float, float, float] = 'k'
17
+ self.fontcolor: str|tuple[float, float, float, float] = 'k'
18
+
19
+ TICK = TickData()
20
+
21
+ class AxData:
22
+ def __init__(self):
23
+ self.facecolor: str|tuple[float, float, float, float] = '#fafafa'
24
+ self.GRID = GRID
25
+ self.TICK = TICK
26
+
27
+ AX = AxData()
28
+
@@ -0,0 +1,31 @@
1
+
2
+
3
+ class CandleFaceColorData:
4
+ def __init__(self):
5
+ self.bull_rise: str|tuple[float, float, float, float] = '#FF2400'
6
+ self.bull_fall: str|tuple[float, float, float, float] = 'w'
7
+ self.bear_fall: str|tuple[float, float, float, float] = '#1E90FF'
8
+ self.bear_rise: str|tuple[float, float, float, float] = 'w'
9
+
10
+ CANDLEFACECOLOR = CandleFaceColorData()
11
+
12
+ class CandleEdgeColorData:
13
+ def __init__(self):
14
+ self.bull_rise: str|tuple[float, float, float, float] = '#FF2400'
15
+ self.bull_fall: str|tuple[float, float, float, float] = '#FF2400'
16
+ self.bear_fall: str|tuple[float, float, float, float] = '#1E90FF'
17
+ self.bear_rise: str|tuple[float, float, float, float] = '#1E90FF'
18
+ self.doji: str|tuple[float, float, float, float] = 'k'
19
+
20
+ CANDLEEDGECOLOR = CandleEdgeColorData()
21
+
22
+ class CandleData:
23
+ def __init__(self):
24
+ self.half_width = 0.24
25
+ self.linewidth = 0.8
26
+ self.line_color: str|tuple[float, float, float, float] = 'k'
27
+ self.FACECOLOR = CANDLEFACECOLOR
28
+ self.EDGECOLOR = CANDLEEDGECOLOR
29
+
30
+ CANDLE = CandleData()
31
+
@@ -0,0 +1,21 @@
1
+ from . import figure, ax, candle, volume, ma, unit, cursor, format
2
+
3
+
4
+ class ConfigData:
5
+ def __init__(self):
6
+ self.FIGURE = figure.FIGURE
7
+ self.UNIT = unit.UNIT
8
+ self.AX = ax.AX
9
+ self.CANDLE = candle.CANDLE
10
+ self.VOLUME = volume.VOLUME
11
+ self.MA = ma.MA
12
+ self.CURSOR = cursor.CURSOR
13
+ self.FORMAT = format.FORMAT
14
+
15
+ DEFAULTCONFIG = ConfigData()
16
+
17
+ DEFAULTCONFIG_EN = ConfigData()
18
+ DEFAULTCONFIG_EN.UNIT = unit.UNIT_EN
19
+ DEFAULTCONFIG_EN.MA = ma.MA_EN
20
+ DEFAULTCONFIG_EN.FORMAT = format.FORMAT_EN
21
+
@@ -0,0 +1,49 @@
1
+
2
+
3
+ class CrossLineData:
4
+ def __init__(self):
5
+ self.edgecolor = 'k'
6
+ self.linewidth = 1
7
+ self.linestyle = '-'
8
+
9
+ CROSSLINE = CrossLineData()
10
+
11
+ class BBoxData:
12
+ def __init__(self):
13
+ self.boxstyle = 'round'
14
+ self.facecolor = 'w'
15
+ self.edgecolor = 'k'
16
+
17
+ BBOX = BBoxData()
18
+
19
+ class Text:
20
+ def __init__(self):
21
+ self.color = 'k'
22
+ self.BBOX = BBOX
23
+
24
+ def to_dict(self):
25
+ data = {}
26
+ for k, v in self.__dict__.items():
27
+ if k == 'BBOX':
28
+ k = k.lower()
29
+ v = self.BBOX.__dict__
30
+ data[k] = v
31
+ return data
32
+
33
+ TEXT = Text()
34
+
35
+ class Box:
36
+ def __init__(self):
37
+ self.edgecolor = 'k'
38
+ self.linewidth = 1.2
39
+
40
+ BOX = Box()
41
+
42
+ class Cursor:
43
+ def __init__(self):
44
+ self.CROSSLINE = CROSSLINE
45
+ self.TEXT = TEXT
46
+ self.BOX = BOX
47
+
48
+ CURSOR = Cursor()
49
+
@@ -0,0 +1,40 @@
1
+
2
+
3
+ class RatioData:
4
+ def __init__(self):
5
+ self.price = 5
6
+ self.volume = 5
7
+
8
+ RATIO = RatioData()
9
+
10
+ class WatermarkData:
11
+ def __init__(self):
12
+ self.alpha = 0.2
13
+ self.color = 'k'
14
+ self.fontsize = 20
15
+
16
+ WATERMARK = WatermarkData()
17
+
18
+ class AdjustData:
19
+ def __init__(self):
20
+ # 여백
21
+ self.top = 0.98
22
+ self.bottom = 0.05
23
+ self.left = 0.01
24
+ self.right = 0.93
25
+ # 플롯간 간격
26
+ self.wspace = 0
27
+ self.hspace = 0
28
+
29
+ ADJUST = AdjustData()
30
+
31
+ class FigureData:
32
+ def __init__(self):
33
+ self.facecolor: str|tuple[float, float, float, float] = '#fafafa'
34
+ self.figsize = (14, 7)
35
+ self.RATIO = RATIO
36
+ self.ADJUST = ADJUST
37
+ self.WATERMARK = WATERMARK
38
+
39
+ FIGURE = FigureData()
40
+
@@ -0,0 +1,51 @@
1
+
2
+
3
+ format_candleinfo_ko = """\
4
+ {dt}
5
+
6
+ 종가:  {close}
7
+ 등락률: {rate}
8
+ 대비:  {compare}
9
+ 시가:  {open}({rate_open})
10
+ 고가:  {high}({rate_high})
11
+ 저가:  {low}({rate_low})
12
+ 거래량: {volume}({rate_volume})\
13
+ """
14
+ format_volumeinfo_ko = """\
15
+ {dt}
16
+
17
+ 거래량:    {volume}
18
+ 거래량증가율: {rate_volume}
19
+ 대비:     {compare}\
20
+ """
21
+
22
+ class FormatData:
23
+ def __init__(self):
24
+ self.candle = format_candleinfo_ko
25
+ self.volume = format_volumeinfo_ko
26
+
27
+ FORMAT = FormatData()
28
+
29
+ format_candleinfo_en = """\
30
+ {dt}
31
+
32
+ close: {close}
33
+ rate: {rate}
34
+ compare: {compare}
35
+ open: {open}({rate_open})
36
+ high: {high}({rate_high})
37
+ low: {low}({rate_low})
38
+ volume: {volume}({rate_volume})\
39
+ """
40
+ format_volumeinfo_en = """\
41
+ {dt}
42
+
43
+ volume: {volume}
44
+ volume rate: {rate_volume}
45
+ compare: {compare}\
46
+ """
47
+
48
+ FORMAT_EN = FormatData()
49
+ FORMAT_EN.candle = format_candleinfo_en
50
+ FORMAT_EN.volume = format_volumeinfo_en
51
+
@@ -0,0 +1,17 @@
1
+
2
+
3
+ class MaData:
4
+ "https://matplotlib.org/stable/gallery/color/named_colors.html"
5
+ def __init__(self):
6
+ self.color_default: str|tuple[float, float, float, float] = 'k'
7
+ self.format = '{}일선'
8
+ self.linewidth = 1
9
+ self.ncol = 10
10
+ self.color_list: list[str|tuple[float, float, float, float]] = ['#8B00FF', '#008000', '#A0522D', '#008B8B', '#FF0080']
11
+ self.ma_list = (5, 20, 60, 120, 240)
12
+
13
+ MA = MaData()
14
+
15
+ MA_EN = MaData()
16
+ MA_EN.format = 'ma{}'
17
+
@@ -0,0 +1,2 @@
1
+ from .config import SLIDERCONFIG, SLIDERCONFIG_EN, SliderConfigData
2
+
@@ -0,0 +1,24 @@
1
+ from .. import config
2
+ from .figure import FIGURE, SliderFigureData
3
+ from .nav import NAV
4
+
5
+
6
+ class SliderData:
7
+ def __init__(self):
8
+ self.NAV = NAV
9
+
10
+ SLIDER = SliderData()
11
+
12
+ class SliderConfigData(config.ConfigData):
13
+ FIGURE: SliderFigureData
14
+ SLIDER: SliderData
15
+
16
+
17
+ SLIDERCONFIG: SliderConfigData = config.DEFAULTCONFIG
18
+ SLIDERCONFIG.FIGURE = FIGURE
19
+ SLIDERCONFIG.SLIDER = SLIDER
20
+
21
+ SLIDERCONFIG_EN: SliderConfigData = config.DEFAULTCONFIG_EN
22
+ SLIDERCONFIG_EN.FIGURE = FIGURE
23
+ SLIDERCONFIG_EN.SLIDER = SLIDER
24
+
@@ -0,0 +1,19 @@
1
+ from .. import figure
2
+
3
+
4
+ class RatioData:
5
+ def __init__(self):
6
+ self.price = 9
7
+ self.volume = 3
8
+ self.none = 2
9
+ self.slider = 1.5
10
+
11
+ RATIO = RatioData()
12
+
13
+ class SliderFigureData(figure.FigureData):
14
+ def __init__(self):
15
+ super().__init__()
16
+ self.RATIO: RatioData = RATIO
17
+
18
+ FIGURE = SliderFigureData()
19
+
@@ -0,0 +1,10 @@
1
+
2
+
3
+ class Nav:
4
+ def __init__(self):
5
+ self.edgecolor = '#2962FF'
6
+ self.facecolor = '#0000002E'
7
+ self.alpha = 0.18
8
+
9
+ NAV = Nav()
10
+
@@ -0,0 +1,19 @@
1
+ from .utils import convert_unit, convert_unit_en
2
+
3
+
4
+ class UnitData:
5
+ def __init__(self):
6
+ self.price = '원'
7
+ self.volume = '주'
8
+ self.digit = 0
9
+ self.digit_volume = 0
10
+ self.func = convert_unit
11
+
12
+ UNIT = UnitData()
13
+
14
+ UNIT_EN = UnitData()
15
+ UNIT_EN.price = ' $'
16
+ UNIT_EN.volume = ' Vol'
17
+ UNIT_EN.digit = 2
18
+ UNIT_EN.func = convert_unit_en
19
+
@@ -0,0 +1,67 @@
1
+
2
+
3
+ def convert_num(num):
4
+ if isinstance(num, float) and num % 1:
5
+ return num
6
+ return int(num)
7
+
8
+
9
+ def float_to_str(num: float, *, digit=0, plus=False):
10
+ if 0 < digit:
11
+ num.__round__(digit)
12
+ text = f'{num:+,.{digit}f}' if plus else f'{num:,.{digit}f}'
13
+ else:
14
+ num = round(num, digit).__int__()
15
+ text = f'{num:+,}' if plus else f'{num:,}'
16
+ return text
17
+
18
+
19
+ unit_ko = {
20
+ '경': 10_000_000_000_000_000,
21
+ '조': 1_000_000_000_000,
22
+ '억': 100_000_000,
23
+ '만': 10_000,
24
+ }
25
+ def convert_unit(value, *, digit=0, word='원', unit_data: dict[str, int]=None):
26
+ if not unit_data:
27
+ unit_data = unit_ko
28
+ # print('ko')
29
+ # print(f'{value=:,}')
30
+ v = abs(value)
31
+ for unit, n in unit_data.items():
32
+ if n <= v:
33
+ # print(f'{n=:,}')
34
+ # print(f'{unit=}')
35
+ num = value / n
36
+ if word.startswith(' '):
37
+ return f'{float_to_str(num, digit=digit)}{unit}{word}'
38
+ return f'{float_to_str(num, digit=digit)}{unit} {word}'
39
+
40
+ if not value % 1:
41
+ value = int(value)
42
+ text = f'{float_to_str(value, digit=digit)}{word}'
43
+ # print(f'{text=}')
44
+ return text
45
+
46
+ unit_en = {
47
+ 'Qd': 1_000_000_000_000_000,
48
+ 'T': 1_000_000_000_000,
49
+ 'B': 1_000_000_000,
50
+ 'M': 1_000_000,
51
+ 'K': 1_000,
52
+ }
53
+ def convert_unit_en(value, *, digit=0, word='$', unit_data: dict[str, int]=None):
54
+ if not unit_data:
55
+ unit_data = unit_en
56
+ # print('en')
57
+ # print(f'{value=:,}')
58
+ return convert_unit(value, digit=digit, word=word, unit_data=unit_data)
59
+
60
+
61
+ if __name__ == '__main__':
62
+ a = 456.123
63
+ print(float_to_str(a))
64
+ print(float_to_str(a, 2))
65
+ print(float_to_str(a, 6))
66
+
67
+