mtcli 3.5.1__tar.gz → 3.6.0.dev0__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 (76) hide show
  1. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/PKG-INFO +2 -2
  2. mtcli-3.6.0.dev0/mtcli/cli.py +32 -0
  3. mtcli-3.6.0.dev0/mtcli/conf.py +199 -0
  4. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/data/csv.py +1 -1
  5. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/bar_model.py +105 -105
  6. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/consecutive_bars_model.py +77 -77
  7. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/unconsecutive_bar_model.py +67 -67
  8. mtcli-3.6.0.dev0/mtcli/plugin.py +18 -0
  9. mtcli-3.6.0.dev0/mtcli/plugin_loader.py +57 -0
  10. mtcli-3.6.0.dev0/mtcli/plugins/hello.py +20 -0
  11. mtcli-3.6.0.dev0/mtcli/plugins/media_movel/__init__.py +5 -0
  12. mtcli-3.5.1/mtcli/plugins/media_movel/command.py → mtcli-3.6.0.dev0/mtcli/plugins/media_movel/cli.py +98 -99
  13. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/media_movel/tests/test_mm.py +13 -13
  14. mtcli-3.6.0.dev0/mtcli/plugins/range_medio/__init__.py +5 -0
  15. mtcli-3.5.1/mtcli/plugins/range_medio/command.py → mtcli-3.6.0.dev0/mtcli/plugins/range_medio/cli.py +32 -33
  16. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/range_medio/models/average_range_model.py +29 -29
  17. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/range_medio/tests/test_rm.py +1 -1
  18. mtcli-3.6.0.dev0/mtcli/plugins/volume_medio/__init__.py +5 -0
  19. mtcli-3.5.1/mtcli/plugins/volume_medio/command.py → mtcli-3.6.0.dev0/mtcli/plugins/volume_medio/cli.py +41 -42
  20. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/volume_medio/models/model_average_volume.py +31 -31
  21. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/volume_medio/tests/test_vm.py +1 -1
  22. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/close_view.py +37 -37
  23. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/full_view.py +65 -65
  24. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/high_view.py +37 -37
  25. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/low_view.py +37 -37
  26. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/min_view.py +42 -42
  27. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/open_view.py +37 -37
  28. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/ranges_view.py +41 -41
  29. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/rates_view.py +41 -41
  30. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/pyproject.toml +4 -6
  31. mtcli-3.5.1/mtcli/commands/conf.py +0 -50
  32. mtcli-3.5.1/mtcli/commands/logs.py +0 -42
  33. mtcli-3.5.1/mtcli/conf.py +0 -102
  34. mtcli-3.5.1/mtcli/mt.py +0 -45
  35. mtcli-3.5.1/mtcli/plugin.py +0 -9
  36. mtcli-3.5.1/mtcli/plugins/media_movel/__init__.py +0 -3
  37. mtcli-3.5.1/mtcli/plugins/range_medio/__init__.py +0 -2
  38. mtcli-3.5.1/mtcli/plugins/volume_medio/__init__.py +0 -3
  39. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/LICENSE +0 -0
  40. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/README.md +0 -0
  41. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/__init__.py +0 -0
  42. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/commands/__init__.py +0 -0
  43. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/commands/bars.py +0 -0
  44. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/conecta.py +0 -0
  45. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/data/__init__.py +0 -0
  46. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/data/base.py +0 -0
  47. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/data/mt5.py +0 -0
  48. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/database.py +0 -0
  49. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/domain/__init__.py +0 -0
  50. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/domain/timeframe.py +0 -0
  51. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/logger.py +0 -0
  52. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/marketdata/__init__.py +0 -0
  53. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/marketdata/tick_cache.py +0 -0
  54. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/marketdata/tick_repository.py +0 -0
  55. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/__init__.py +0 -0
  56. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/bars_model.py +0 -0
  57. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/chart_model.py +0 -0
  58. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/conf_model.py +0 -0
  59. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/rates_model.py +0 -0
  60. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/models/signals_model.py +0 -0
  61. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/mt5_context.py +0 -0
  62. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/__init__.py +0 -0
  63. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/media_movel/conf.py +0 -0
  64. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/media_movel/models/__init__.py +0 -0
  65. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/media_movel/models/model_media_movel.py +0 -0
  66. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/media_movel/tests/__init__.py +0 -0
  67. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/media_movel/tests/test_model_media_movel.py +0 -0
  68. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/range_medio/conf.py +0 -0
  69. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/range_medio/models/__init__.py +0 -0
  70. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/range_medio/tests/__init__.py +0 -0
  71. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/volume_medio/conf.py +0 -0
  72. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/volume_medio/models/__init__.py +0 -0
  73. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/plugins/volume_medio/tests/__init__.py +0 -0
  74. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/__init__.py +0 -0
  75. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/vars_view.py +0 -0
  76. {mtcli-3.5.1 → mtcli-3.6.0.dev0}/mtcli/views/volumes_view.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtcli
3
- Version: 3.5.1
3
+ Version: 3.6.0.dev0
4
4
  Summary: Aplicativo CLI para exibir gráficos do MetaTrader 5 screen reader friendly
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -8,7 +8,7 @@ Keywords: trading,candlestick,metatrader5,mt5,cli,price-action
8
8
  Author: Valmir França da Silva
9
9
  Author-email: vfranca3@gmail.com
10
10
  Requires-Python: >=3.10,<3.14.0
11
- Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Financial and Insurance Industry
13
13
  Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3.10
@@ -0,0 +1,32 @@
1
+ """
2
+ Comando principal do mtcli.
3
+ """
4
+
5
+ import click
6
+ from mtcli.plugin_loader import load_plugins
7
+
8
+ # --- CLI principal ---
9
+ @click.group(context_settings={"max_content_width": 120})
10
+ @click.version_option(package_name="mtcli")
11
+ def mt():
12
+ """
13
+ MTCLI - CLI para gráficos candlestick screen reader friendly.
14
+
15
+ Comandos disponíveis:
16
+ - Subcomandos (bars, conf, logs)
17
+ - Plugins internos e externos
18
+ """
19
+ pass
20
+
21
+ # --- Carrega subcomandos do mt e plugins ---
22
+ # Os comandos do diretório commands são registrados aqui diretamente
23
+ from mtcli.commands import bars
24
+
25
+ mt.add_command(bars.bars, name="bars")
26
+
27
+ # --- Carrega plugins internos e externos via plugin_loader ---
28
+ load_plugins(mt)
29
+
30
+ # --- Entry point para execução direta ---
31
+ if __name__ == "__main__":
32
+ mt()
@@ -0,0 +1,199 @@
1
+ """
2
+ Configurações principais do mtcli.
3
+
4
+ Este módulo centraliza a leitura de configurações provenientes de:
5
+
6
+ 1. Variáveis de ambiente
7
+ 2. Arquivo mtcli.ini
8
+
9
+ As variáveis de ambiente sempre têm prioridade sobre o arquivo INI.
10
+
11
+ Também fornece utilidades para obter o caminho de arquivos do
12
+ terminal MetaTrader5 e selecionar a fonte de dados (CSV ou MT5).
13
+
14
+ O acesso ao terminal MT5 é realizado apenas sob demanda para evitar
15
+ efeitos colaterais durante a importação do módulo (import side effects),
16
+ facilitando testes automatizados e execução em ambientes CI/CD.
17
+ """
18
+
19
+ import os
20
+ import configparser
21
+
22
+ import MetaTrader5 as mt5
23
+
24
+ from mtcli.mt5_context import mt5_conexao
25
+
26
+ # ---------------------------------------------------------
27
+ # Carregamento do arquivo de configuração
28
+ # ---------------------------------------------------------
29
+
30
+ CONFIG_FILE = "mtcli.ini"
31
+ SECTION = "DEFAULT"
32
+
33
+ config = configparser.ConfigParser()
34
+ config.read(CONFIG_FILE)
35
+
36
+
37
+ def get_config_value(key: str, cast=None, fallback=None):
38
+ """
39
+ Retorna um valor de configuração.
40
+
41
+ A prioridade de leitura é:
42
+ 1. Variável de ambiente
43
+ 2. Arquivo mtcli.ini
44
+ 3. Valor fallback
45
+
46
+ Args:
47
+ key (str): Nome da chave de configuração.
48
+ cast (type | None): Tipo de conversão (ex: int, float).
49
+ fallback (Any): Valor padrão caso não encontrado.
50
+
51
+ Returns:
52
+ Any: valor convertido ou fallback.
53
+ """
54
+ value = os.getenv(key)
55
+
56
+ if value is None:
57
+ try:
58
+ if cast == int:
59
+ value = config.getint(SECTION, key, fallback=fallback)
60
+ elif cast == float:
61
+ value = config.getfloat(SECTION, key, fallback=fallback)
62
+ else:
63
+ value = config.get(SECTION, key, fallback=fallback)
64
+ except (configparser.NoOptionError, ValueError):
65
+ value = fallback
66
+ else:
67
+ if cast:
68
+ try:
69
+ value = cast(value)
70
+ except ValueError:
71
+ value = fallback
72
+
73
+ return value
74
+
75
+
76
+ # ---------------------------------------------------------
77
+ # Configurações gerais
78
+ # ---------------------------------------------------------
79
+
80
+ SYMBOL = get_config_value("symbol", fallback="WIN$N")
81
+ DIGITOS = get_config_value("digitos", cast=int, fallback=2)
82
+ PERIOD = get_config_value("period", fallback="D1")
83
+ BARS = get_config_value("count", cast=int, fallback=999)
84
+
85
+ VIEW = get_config_value("view", fallback="ch")
86
+ VOLUME = get_config_value("volume", fallback="tick")
87
+ DATE = get_config_value("date", fallback="")
88
+
89
+ # ---------------------------------------------------------
90
+ # Configurações de leitura de candles
91
+ # ---------------------------------------------------------
92
+
93
+ LATERAL = get_config_value("lateral", fallback="doji")
94
+ ALTA = get_config_value("alta", fallback="verde")
95
+ BAIXA = get_config_value("baixa", fallback="vermelho")
96
+
97
+ ROMPIMENTO_ALTA = get_config_value("rompimento_alta", fallback="c")
98
+ ROMPIMENTO_BAIXA = get_config_value("rompimento_baixa", fallback="v")
99
+
100
+ PERCENTUAL_ROMPIMENTO = get_config_value(
101
+ "percentual_rompimento", cast=int, fallback=50
102
+ )
103
+
104
+ PERCENTUAL_DOJI = get_config_value(
105
+ "percentual_doji", cast=int, fallback=10
106
+ )
107
+
108
+ # ---------------------------------------------------------
109
+ # Configurações de padrões de barra
110
+ # ---------------------------------------------------------
111
+
112
+ UP_BAR = get_config_value("up_bar", fallback="asc")
113
+ DOWN_BAR = get_config_value("down_bar", fallback="desc")
114
+
115
+ INSIDE_BAR = get_config_value("inside_bar", fallback="ib")
116
+ OUTSIDE_BAR = get_config_value("outside_bar", fallback="ob")
117
+
118
+ SOMBRA_SUPERIOR = get_config_value("sombra_superior", fallback="top")
119
+ SOMBRA_INFERIOR = get_config_value("sombra_inferior", fallback="bottom")
120
+
121
+ # ---------------------------------------------------------
122
+ # Fonte de dados
123
+ # ---------------------------------------------------------
124
+
125
+ DATA_SOURCE = get_config_value("dados", fallback="mt5").lower()
126
+
127
+ # caminho inicial (pode vir do ini/env)
128
+ _INITIAL_CSV_PATH = get_config_value("mt5_pasta", fallback="")
129
+
130
+
131
+ def get_csv_path():
132
+ """
133
+ Retorna o caminho da pasta de arquivos do MT5 ou CSV.
134
+
135
+ Se o caminho não estiver definido no mtcli.ini ou nas
136
+ variáveis de ambiente, o terminal MT5 é consultado para
137
+ descobrir automaticamente a pasta MQL5/Files.
138
+
139
+ Returns:
140
+ str: caminho normalizado da pasta de arquivos.
141
+ """
142
+ if _INITIAL_CSV_PATH:
143
+ path = _INITIAL_CSV_PATH
144
+ else:
145
+ with mt5_conexao():
146
+ terminal_info = mt5.terminal_info()
147
+
148
+ if terminal_info is None:
149
+ raise RuntimeError(
150
+ "Não foi possível obter as informações do terminal MT5."
151
+ )
152
+
153
+ path = os.path.join(terminal_info.data_path, "MQL5", "Files")
154
+
155
+ return os.path.normpath(path) + os.sep
156
+
157
+
158
+ # ---------------------------------------------------------
159
+ # Factory de DataSource
160
+ # ---------------------------------------------------------
161
+
162
+ def get_data_source(source=None):
163
+ """
164
+ Retorna a fonte de dados configurada.
165
+
166
+ Args:
167
+ source (str | None): sobrescreve DATA_SOURCE se fornecido.
168
+
169
+ Returns:
170
+ CsvDataSource | MT5DataSource
171
+
172
+ Raises:
173
+ ValueError: se a fonte de dados não for reconhecida.
174
+ """
175
+ from mtcli.data import CsvDataSource, MT5DataSource
176
+
177
+ src = source.lower() if source else DATA_SOURCE
178
+
179
+ if src == "csv":
180
+ return CsvDataSource()
181
+
182
+ if src == "mt5":
183
+ return MT5DataSource()
184
+
185
+ raise ValueError(f"Fonte de dados desconhecida: {src}")
186
+
187
+
188
+ # ---------------------------------------------------------
189
+ # Timeframes suportados
190
+ # ---------------------------------------------------------
191
+
192
+ _HOURS = [12, 8, 6, 4, 3, 2, 1]
193
+ _MINUTES = [30, 20, 15, 12, 10, 6, 5, 4, 3, 2, 1]
194
+
195
+ TIMEFRAMES = (
196
+ ["mn1", "w1", "d1"]
197
+ + [f"h{i}" for i in _HOURS]
198
+ + [f"m{i}" for i in _MINUTES]
199
+ )
@@ -16,7 +16,7 @@ class CsvDataSource(DataSourceBase):
16
16
 
17
17
  def get_data(self, symbol, period, count=100):
18
18
  """Retorna dados CSV em uma lista de lista."""
19
- file_path = os.path.join(conf.csv_path, f"{symbol}{period}.csv")
19
+ file_path = os.path.join(conf._INITIAL_CSV_PATH, f"{symbol}{period}.csv")
20
20
  logger.info(f"Iniciando coleta de dados via CSV: {file_path}.")
21
21
  csv_data = []
22
22
  try:
@@ -1,105 +1,105 @@
1
- """Módulo da classe model da barra."""
2
-
3
- from datetime import datetime
4
-
5
- from mtcli import conf
6
-
7
-
8
- class BarModel:
9
- """Classe do model da barra."""
10
-
11
- def __init__(self, rate):
12
- """Model da barra."""
13
- self.datetime = rate[0]
14
- self.date = self.__get_date()
15
- self.time = self.__get_time()
16
- self.open = float(rate[1])
17
- self.high = float(rate[2])
18
- self.low = float(rate[3])
19
- self.close = float(rate[4])
20
- self.volume = int(rate[5])
21
- self.volume_real = int(rate[6])
22
- self.range = self.__get_range()
23
- self.body = self.__get_body()
24
- self.top = self.__get_top()
25
- self.bottom = self.__get_bottom()
26
- self.body_range = self.__get_body_range()
27
- self.trend = self.__get_trend()
28
- self.medium_point = self.__get_medium_point()
29
-
30
- def __get_date(self):
31
- """Obtem a data da barra no formato YYYY-MM-DD."""
32
- data = datetime.strptime(self.datetime, "%Y.%m.%d %H:%M:%S")
33
- return data.date()
34
-
35
- def __get_time(self):
36
- """Obtem o horário da barra no formato HH:MM:SS."""
37
- hora = datetime.strptime(self.datetime, "%Y.%m.%d %H:%M:%S")
38
- hora = hora.time()
39
- return hora.strftime("%H:%M")
40
-
41
- def __get_range(self):
42
- """Obtem o range da barra."""
43
- return self.high - self.low
44
-
45
- def __get_body(self):
46
- """Calcula o range relativo do corpo da barra em porcentagem."""
47
- if self.range == 0:
48
- return 0
49
-
50
- return round((self.close - self.open) / self.range * 100)
51
-
52
- def __get_top(self):
53
- """Calcula o range relativo da sombra superior da barra em porcentagem."""
54
- high = self.high
55
- open = self.open
56
- close = self.close
57
- range = self.range
58
-
59
- if close >= open:
60
- top = high - close
61
- else:
62
- top = high - open
63
-
64
- if range == 0:
65
- return 0
66
-
67
- return round(top / range * 100)
68
-
69
- def __get_bottom(self):
70
- """Obtem o range relativo da sombra inferior da barra em porcentagem."""
71
- low = self.low
72
- open = self.open
73
- close = self.close
74
- range = self.range
75
-
76
- if close >= open:
77
- bottom = open - low
78
- else:
79
- bottom = close - low
80
-
81
- if range == 0:
82
- return 0
83
-
84
- return round(bottom / range * 100)
85
-
86
- def __get_body_range(self):
87
- """Calcula o range do corpo da barra."""
88
- return abs(self.close - self.open)
89
-
90
- def __get_trend(self):
91
- """Obtem a tendência da barra."""
92
- b = self.body
93
-
94
- if b > 0:
95
- trend = conf.alta
96
- elif b < 0:
97
- trend = conf.baixa
98
- else:
99
- trend = conf.lateral
100
-
101
- return trend
102
-
103
- def __get_medium_point(self):
104
- """Obtem o ponto médio da barra."""
105
- return round(self.low + self.range / 2, conf.digitos)
1
+ """Módulo da classe model da barra."""
2
+
3
+ from datetime import datetime
4
+
5
+ from mtcli import conf
6
+
7
+
8
+ class BarModel:
9
+ """Classe do model da barra."""
10
+
11
+ def __init__(self, rate):
12
+ """Model da barra."""
13
+ self.datetime = rate[0]
14
+ self.date = self.__get_date()
15
+ self.time = self.__get_time()
16
+ self.open = float(rate[1])
17
+ self.high = float(rate[2])
18
+ self.low = float(rate[3])
19
+ self.close = float(rate[4])
20
+ self.volume = int(rate[5])
21
+ self.volume_real = int(rate[6])
22
+ self.range = self.__get_range()
23
+ self.body = self.__get_body()
24
+ self.top = self.__get_top()
25
+ self.bottom = self.__get_bottom()
26
+ self.body_range = self.__get_body_range()
27
+ self.trend = self.__get_trend()
28
+ self.medium_point = self.__get_medium_point()
29
+
30
+ def __get_date(self):
31
+ """Obtem a data da barra no formato YYYY-MM-DD."""
32
+ data = datetime.strptime(self.datetime, "%Y.%m.%d %H:%M:%S")
33
+ return data.date()
34
+
35
+ def __get_time(self):
36
+ """Obtem o horário da barra no formato HH:MM:SS."""
37
+ hora = datetime.strptime(self.datetime, "%Y.%m.%d %H:%M:%S")
38
+ hora = hora.time()
39
+ return hora.strftime("%H:%M")
40
+
41
+ def __get_range(self):
42
+ """Obtem o range da barra."""
43
+ return self.high - self.low
44
+
45
+ def __get_body(self):
46
+ """Calcula o range relativo do corpo da barra em porcentagem."""
47
+ if self.range == 0:
48
+ return 0
49
+
50
+ return round((self.close - self.open) / self.range * 100)
51
+
52
+ def __get_top(self):
53
+ """Calcula o range relativo da sombra superior da barra em porcentagem."""
54
+ high = self.high
55
+ open = self.open
56
+ close = self.close
57
+ range = self.range
58
+
59
+ if close >= open:
60
+ top = high - close
61
+ else:
62
+ top = high - open
63
+
64
+ if range == 0:
65
+ return 0
66
+
67
+ return round(top / range * 100)
68
+
69
+ def __get_bottom(self):
70
+ """Obtem o range relativo da sombra inferior da barra em porcentagem."""
71
+ low = self.low
72
+ open = self.open
73
+ close = self.close
74
+ range = self.range
75
+
76
+ if close >= open:
77
+ bottom = open - low
78
+ else:
79
+ bottom = close - low
80
+
81
+ if range == 0:
82
+ return 0
83
+
84
+ return round(bottom / range * 100)
85
+
86
+ def __get_body_range(self):
87
+ """Calcula o range do corpo da barra."""
88
+ return abs(self.close - self.open)
89
+
90
+ def __get_trend(self):
91
+ """Obtem a tendência da barra."""
92
+ b = self.body
93
+
94
+ if b > 0:
95
+ trend = conf.ALTA
96
+ elif b < 0:
97
+ trend = conf.BAIXA
98
+ else:
99
+ trend = conf.LATERAL
100
+
101
+ return trend
102
+
103
+ def __get_medium_point(self):
104
+ """Obtem o ponto médio da barra."""
105
+ return round(self.low + self.range / 2, conf.DIGITOS)
@@ -1,77 +1,77 @@
1
- """Módulo da classe model de leituras de barras consecutivas."""
2
-
3
- from mtcli import conf
4
-
5
-
6
- class ConsecutiveBarsModel:
7
- """Classe model da leitura de barras consecutivas."""
8
-
9
- def __init__(self, bodys, opens, closes, highs, lows, volumes=[]):
10
- """Model da leitura de barras consecutivas."""
11
- self.bodys = bodys
12
- self.opens = opens
13
- self.closes = closes
14
- self.highs = highs
15
- self.lows = lows
16
- self.volumes = volumes
17
-
18
- def gap(self):
19
- """Leitura do gap de rompimento de duas barras."""
20
- if self.__is_gap():
21
- if self.bodys[1] > 0:
22
- gap = self.closes[1] - self.highs[0]
23
- if self.bodys[1] < 0:
24
- gap = self.lows[0] - self.closes[1]
25
- return gap
26
- return ""
27
-
28
- def __is_gap(self):
29
- """Verifica se existe gap de rompimento entre duas barras."""
30
- if self.bodys[1] == 0:
31
- return False
32
- if self.bodys[1] > 0 and self.closes[1] <= self.highs[0]:
33
- return False
34
- if self.bodys[1] < 0 and self.closes[1] >= self.lows[0]:
35
- return False
36
- return True
37
-
38
- def sequencia(self):
39
- """Leitura da tendência da sequência de duas barras."""
40
- if self.highs[1] > self.highs[0] and self.lows[1] > self.lows[0]:
41
- return conf.up_bar
42
- if self.highs[1] < self.highs[0] and self.lows[1] < self.lows[0]:
43
- return conf.down_bar
44
- if self.highs[1] <= self.highs[0] and self.lows[1] >= self.lows[0]:
45
- return conf.inside_bar
46
- if self.highs[1] > self.highs[0] and self.lows[1] < self.lows[0]:
47
- return conf.outside_bar
48
- return ""
49
-
50
- def volume(self):
51
- """Comparação entre volumes consecutivos."""
52
- sequencia = ""
53
- anterior = self.volumes[0]
54
- posterior = self.volumes[1]
55
- if posterior > anterior:
56
- sequencia = conf.alta
57
- if posterior < anterior:
58
- sequencia = conf.baixa
59
- return sequencia
60
-
61
- def continuacao(self):
62
- """Verifica se há continuação de movimento com corpo na mesma direção."""
63
- return self.bodys[0] * self.bodys[1] > 0 and abs(self.bodys[1]) > abs(
64
- self.bodys[0]
65
- )
66
-
67
- def reversao(self):
68
- """Verifica reversão pelo corpo oposto com maior intensidade."""
69
- return self.bodys[0] * self.bodys[1] < 0 and abs(self.bodys[1]) > abs(
70
- self.bodys[0]
71
- )
72
-
73
- def volume_spike(self, fator=2):
74
- """Detecta clímax de volume (volume da segunda barra bem maior)."""
75
- if len(self.volumes) < 2:
76
- return False
77
- return self.volumes[1] > self.volumes[0] * fator
1
+ """Módulo da classe model de leituras de barras consecutivas."""
2
+
3
+ from mtcli import conf
4
+
5
+
6
+ class ConsecutiveBarsModel:
7
+ """Classe model da leitura de barras consecutivas."""
8
+
9
+ def __init__(self, bodys, opens, closes, highs, lows, volumes=[]):
10
+ """Model da leitura de barras consecutivas."""
11
+ self.bodys = bodys
12
+ self.opens = opens
13
+ self.closes = closes
14
+ self.highs = highs
15
+ self.lows = lows
16
+ self.volumes = volumes
17
+
18
+ def gap(self):
19
+ """Leitura do gap de rompimento de duas barras."""
20
+ if self.__is_gap():
21
+ if self.bodys[1] > 0:
22
+ gap = self.closes[1] - self.highs[0]
23
+ if self.bodys[1] < 0:
24
+ gap = self.lows[0] - self.closes[1]
25
+ return gap
26
+ return ""
27
+
28
+ def __is_gap(self):
29
+ """Verifica se existe gap de rompimento entre duas barras."""
30
+ if self.bodys[1] == 0:
31
+ return False
32
+ if self.bodys[1] > 0 and self.closes[1] <= self.highs[0]:
33
+ return False
34
+ if self.bodys[1] < 0 and self.closes[1] >= self.lows[0]:
35
+ return False
36
+ return True
37
+
38
+ def sequencia(self):
39
+ """Leitura da tendência da sequência de duas barras."""
40
+ if self.highs[1] > self.highs[0] and self.lows[1] > self.lows[0]:
41
+ return conf.UP_BAR
42
+ if self.highs[1] < self.highs[0] and self.lows[1] < self.lows[0]:
43
+ return conf.DOWN_BAR
44
+ if self.highs[1] <= self.highs[0] and self.lows[1] >= self.lows[0]:
45
+ return conf.INSIDE_BAR
46
+ if self.highs[1] > self.highs[0] and self.lows[1] < self.lows[0]:
47
+ return conf.OUTSIDE_BAR
48
+ return ""
49
+
50
+ def volume(self):
51
+ """Comparação entre volumes consecutivos."""
52
+ sequencia = ""
53
+ anterior = self.volumes[0]
54
+ posterior = self.volumes[1]
55
+ if posterior > anterior:
56
+ sequencia = conf.ALTA
57
+ if posterior < anterior:
58
+ sequencia = conf.BAIXA
59
+ return sequencia
60
+
61
+ def continuacao(self):
62
+ """Verifica se há continuação de movimento com corpo na mesma direção."""
63
+ return self.bodys[0] * self.bodys[1] > 0 and abs(self.bodys[1]) > abs(
64
+ self.bodys[0]
65
+ )
66
+
67
+ def reversao(self):
68
+ """Verifica reversão pelo corpo oposto com maior intensidade."""
69
+ return self.bodys[0] * self.bodys[1] < 0 and abs(self.bodys[1]) > abs(
70
+ self.bodys[0]
71
+ )
72
+
73
+ def volume_spike(self, fator=2):
74
+ """Detecta clímax de volume (volume da segunda barra bem maior)."""
75
+ if len(self.volumes) < 2:
76
+ return False
77
+ return self.volumes[1] > self.volumes[0] * fator