/ candlesticks.py
candlesticks.py
  1  # SPDX-FileCopyrightText: Copyright (c) 2021 Jose David
  2  #
  3  # SPDX-License-Identifier: MIT
  4  """
  5  `candlesticks`
  6  ================================================================================
  7  
  8  Graphical representation of the stock movement in candlestick form
  9  
 10  
 11  * Author(s): Jose David
 12  
 13  Implementation Notes
 14  --------------------
 15  
 16  * Adafruit CircuitPython firmware for the supported boards:
 17    https://github.com/adafruit/circuitpython/releases
 18  
 19  """
 20  
 21  # pylint: disable=too-many-lines, too-many-instance-attributes, too-many-arguments
 22  # pylint: disable=too-many-locals, too-many-statements, invalid-name, too-few-public-methods
 23  
 24  import math
 25  import displayio
 26  from vectorio import Rectangle
 27  
 28  __version__ = "0.0.0-auto.0"
 29  __repo__ = "https://github.com/jposada202020/CircuitPython_Candlesticks.git"
 30  
 31  
 32  class Candlestick:
 33      """A graphical candlestick representation
 34  
 35      :param int dist_x: number of segments in each bar
 36  
 37      :param int openp: Stock open price
 38      :param int close: Stock close price
 39      :param int high: Stock high price
 40      :param int low: Stock low price
 41  
 42      :param int color_green: When stock close price is higher thant the price opening
 43       candlestick are representing by a green color. This allows the selection of the
 44       color of your choice
 45      :param int color_red: When stock close price is lower thant the price opening
 46       candlestick are representing by a red color. This allows the selection of the
 47       color of your choice
 48  
 49      :param int screen_ref: Distance in pixels from the left to the screem to locate
 50       the candlestick. This allows to present different candlesticks in the same screen
 51  
 52  
 53      **Quickstart: Importing and using Candlestick**
 54  
 55      Here is one way of importing the `Candlestick` class, so you can use it as
 56      the name ``my_candle``:
 57  
 58      .. code-block:: python
 59  
 60          from CircuitPython_Candlesticks.candlesticks import Candlestick as Candlestick
 61  
 62      Now you can create a plane at pixel position x=100, open price=60 close price=30
 63      high price=80 low price=5 using:
 64  
 65      .. code-block:: python
 66  
 67          my_candle = Candlestick(100, 60, 30, 80, 5)
 68  
 69      Once you set up your display, you can now add ``my_candle`` to your display using:
 70  
 71      .. code-block:: python
 72  
 73          display.show(my_plane) # add the group to the display
 74  
 75      If you want to have multiple display elements, you can create a group and then
 76      append the plane and the other elements to the group.  Then, you can add the full
 77      group to the display as in this example:
 78  
 79      .. code-block:: python
 80  
 81          my_candle = Candlestick(100, 60, 30, 80, 5)
 82          my_group = displayio.Group() # make a group
 83          my_group.append(my_plane) # Add my_plane to the group
 84  
 85          #
 86          # Append other display elements to the group
 87          #
 88  
 89          display.show(my_group) # add the group to the display
 90  
 91  
 92      **Summary: Cartesian Features and input variables**
 93  
 94      The `Candlestick` class has some options for controlling its position, appearance,
 95      through a collection of input variables:
 96  
 97          - **position**: ``x``
 98  
 99          - **color**: ``color_green``, ``color_red``
100  
101  
102      .. figure:: candlestick.png
103        :scale: 90 %
104        :alt: Diagram of layout coordinates
105  
106        Diagram showing 5 different candlesticks.
107  
108      """
109  
110      def __init__(
111          self,
112          dist_x: int,
113          openp: int,
114          close: int,
115          high: int,
116          low: int,
117          color_green: int = 0x00FF00,
118          color_red: int = 0xFF0000,
119          screen_ref: int = 180,
120      ) -> None:
121  
122          self._my_group = displayio.Group()
123          self._dist_x = dist_x
124          self.bitmap = displayio.Bitmap(high - low, 12, 5)
125          self._candlestick_palette = displayio.Palette(2)
126          self._candlestick_palette.make_transparent(0)
127  
128          self.body_palette = displayio.Palette(2)
129          self.body_palette.make_transparent(0)
130          if openp > close:
131              self.body_palette[1] = color_red
132              self._candlestick_palette[1] = color_red
133          else:
134              self.body_palette[1] = color_green
135              self._candlestick_palette[1] = color_green
136  
137          if openp > close:
138              self._top = openp
139              self._bottom = close
140          else:
141              self._top = close
142              self._bottom = openp
143  
144          self._high = high
145          self._low = low
146  
147          self.screen_ref = screen_ref
148  
149          self._draw_lines()
150  
151      def _draw_lines(self):
152          top_line_height = int(math.fabs(self._high - self._top))
153          if top_line_height == 0:
154              top_line_height = 1
155  
156          top_line = Rectangle(
157              pixel_shader=self.body_palette,
158              width=1,
159              height=top_line_height,
160              x=self._dist_x,
161              y=self.screen_ref - self._high,
162              color_index=1,
163          )
164  
165          body_height = int(math.fabs(self._top - self._bottom))
166  
167          body = Rectangle(
168              pixel_shader=self.body_palette,
169              width=10,
170              height=body_height,
171              x=self._dist_x - 5,
172              y=self.screen_ref - self._top,
173              color_index=1,
174          )
175  
176          bottom_line_height = int(math.fabs(self._bottom - self._low))
177          if bottom_line_height == 0:
178              bottom_line_height = 1
179  
180          bottom_line = Rectangle(
181              pixel_shader=self.body_palette,
182              width=1,
183              height=bottom_line_height,
184              x=self._dist_x,
185              y=self.screen_ref - self._bottom,
186              color_index=1,
187          )
188  
189          self._my_group.append(top_line)
190          self._my_group.append(body)
191          self._my_group.append(bottom_line)
192  
193          self.my_rep = self._my_group