mtcli 3.6.0.dev1__tar.gz → 3.7.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 (76) hide show
  1. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/PKG-INFO +1 -1
  2. mtcli-3.7.0/mtcli/cli.py +74 -0
  3. mtcli-3.7.0/mtcli/commands/conf.py +44 -0
  4. mtcli-3.7.0/mtcli/commands/doctor.py +194 -0
  5. mtcli-3.7.0/mtcli/conf.py +309 -0
  6. mtcli-3.7.0/mtcli/config_registre.py +41 -0
  7. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/data/csv.py +31 -31
  8. mtcli-3.7.0/mtcli/logger.py +136 -0
  9. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/consecutive_bars_model.py +77 -77
  10. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/rates_model.py +41 -41
  11. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/unconsecutive_bar_model.py +67 -67
  12. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugin.py +18 -18
  13. mtcli-3.7.0/mtcli/plugin_loader.py +123 -0
  14. mtcli-3.7.0/mtcli/plugin_manager.py +27 -0
  15. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/__init__.py +5 -5
  16. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/tests/test_mm.py +13 -13
  17. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/range_medio/cli.py +32 -32
  18. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/range_medio/models/average_range_model.py +29 -29
  19. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/range_medio/tests/test_rm.py +11 -11
  20. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/volume_medio/cli.py +41 -41
  21. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/volume_medio/models/model_average_volume.py +31 -31
  22. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/volume_medio/tests/test_vm.py +21 -21
  23. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/close_view.py +37 -37
  24. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/full_view.py +65 -65
  25. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/high_view.py +37 -37
  26. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/low_view.py +37 -37
  27. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/min_view.py +42 -42
  28. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/open_view.py +37 -37
  29. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/ranges_view.py +41 -41
  30. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/rates_view.py +41 -41
  31. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/pyproject.toml +2 -2
  32. mtcli-3.6.0.dev1/mtcli/cli.py +0 -34
  33. mtcli-3.6.0.dev1/mtcli/conf.py +0 -199
  34. mtcli-3.6.0.dev1/mtcli/logger.py +0 -47
  35. mtcli-3.6.0.dev1/mtcli/plugin_loader.py +0 -97
  36. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/LICENSE +0 -0
  37. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/README.md +0 -0
  38. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/__init__.py +0 -0
  39. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/commands/__init__.py +0 -0
  40. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/commands/bars.py +0 -0
  41. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/conecta.py +0 -0
  42. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/data/__init__.py +0 -0
  43. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/data/base.py +0 -0
  44. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/data/mt5.py +0 -0
  45. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/database.py +0 -0
  46. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/domain/__init__.py +0 -0
  47. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/domain/timeframe.py +0 -0
  48. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/marketdata/__init__.py +0 -0
  49. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/marketdata/tick_cache.py +0 -0
  50. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/marketdata/tick_repository.py +0 -0
  51. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/__init__.py +0 -0
  52. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/bar_model.py +0 -0
  53. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/bars_model.py +0 -0
  54. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/chart_model.py +0 -0
  55. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/conf_model.py +0 -0
  56. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/models/signals_model.py +0 -0
  57. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/mt5_context.py +0 -0
  58. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/__init__.py +0 -0
  59. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/exemplo.py-dist +0 -0
  60. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/cli.py +0 -0
  61. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/conf.py +0 -0
  62. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/models/__init__.py +0 -0
  63. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/models/model_media_movel.py +0 -0
  64. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/tests/__init__.py +0 -0
  65. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/media_movel/tests/test_model_media_movel.py +0 -0
  66. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/range_medio/__init__.py +0 -0
  67. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/range_medio/conf.py +0 -0
  68. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/range_medio/models/__init__.py +0 -0
  69. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/range_medio/tests/__init__.py +0 -0
  70. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/volume_medio/__init__.py +0 -0
  71. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/volume_medio/conf.py +0 -0
  72. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/volume_medio/models/__init__.py +0 -0
  73. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/plugins/volume_medio/tests/__init__.py +0 -0
  74. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/__init__.py +0 -0
  75. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/vars_view.py +0 -0
  76. {mtcli-3.6.0.dev1 → mtcli-3.7.0}/mtcli/views/volumes_view.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtcli
3
- Version: 3.6.0.dev1
3
+ Version: 3.7.0
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
@@ -0,0 +1,74 @@
1
+ """
2
+ CLI principal do mtcli.
3
+
4
+ Este módulo define o grupo principal `mt`
5
+ e inicializa o carregamento de plugins.
6
+ """
7
+
8
+ import click
9
+
10
+ from mtcli.plugin_loader import load_plugins
11
+ from mtcli.logger import setup_logger
12
+
13
+ from .commands.bars import bars
14
+ from .commands.doctor import doctor
15
+
16
+ logger = setup_logger(__name__)
17
+
18
+
19
+ @click.group(context_settings={"max_content_width": 120})
20
+ @click.version_option(package_name="mtcli")
21
+ def mt():
22
+ """
23
+ CLI principal do mtcli.
24
+
25
+ Exibe gráficos e informações de mercado
26
+ em formato textual compatível com leitores de tela.
27
+ """
28
+ pass
29
+
30
+
31
+ # ---------------------------------------------------------
32
+ # Comandos internos
33
+ # ---------------------------------------------------------
34
+
35
+ mt.add_command(doctor, name="doctor")
36
+ mt.add_command(bars, name="bars")
37
+ mt.add_command(doctor, name="dr")
38
+
39
+
40
+ # ---------------------------------------------------------
41
+ # Carregamento de plugins
42
+ # ---------------------------------------------------------
43
+
44
+ loaded_plugins = load_plugins(mt)
45
+
46
+ logger.info("Plugins carregados: %s", loaded_plugins)
47
+
48
+
49
+ # ---------------------------------------------------------
50
+ # Comando utilitário: listar plugins
51
+ # ---------------------------------------------------------
52
+
53
+ @mt.command(name="plugins")
54
+ def list_plugins():
55
+ """
56
+ Lista os plugins atualmente carregados no mtcli.
57
+ """
58
+
59
+ if not loaded_plugins:
60
+ click.echo("Nenhum plugin carregado.")
61
+ return
62
+
63
+ click.echo("Plugins carregados:\n")
64
+
65
+ for name in loaded_plugins:
66
+ click.echo(f" {name}")
67
+
68
+
69
+ # ---------------------------------------------------------
70
+ # Entry point
71
+ # ---------------------------------------------------------
72
+
73
+ if __name__ == "__main__":
74
+ mt()
@@ -0,0 +1,44 @@
1
+ """
2
+ Comando para exibir configurações disponíveis.
3
+ """
4
+
5
+ import click
6
+
7
+ from mtcli.config_registry import registry
8
+ from mtcli.conf import conf
9
+
10
+
11
+ @click.command()
12
+ @click.argument("section", required=False)
13
+ def conf_cmd(section):
14
+ """
15
+ Exibe configurações disponíveis.
16
+
17
+ Exemplos:
18
+
19
+ mt conf
20
+ mt conf renko
21
+ """
22
+
23
+ if section:
24
+ options = registry.get_section(section)
25
+ else:
26
+ options = registry.get_all()
27
+
28
+ if not options:
29
+ click.echo("Nenhuma configuração registrada.")
30
+ return
31
+
32
+ for opt in options:
33
+
34
+ value = conf.get(opt.name, section=opt.section, default=opt.default)
35
+
36
+ click.echo(
37
+ f"{opt.section}.{opt.name} = {value} "
38
+ f"(default={opt.default})"
39
+ )
40
+
41
+ if opt.description:
42
+ click.echo(f" {opt.description}")
43
+
44
+ click.echo()
@@ -0,0 +1,194 @@
1
+ """
2
+ Comando de diagnóstico do mtcli.
3
+
4
+ Este comando executa uma série de verificações básicas para ajudar
5
+ a identificar problemas de instalação, configuração ou carregamento
6
+ de plugins no ambiente do mtcli.
7
+
8
+ As verificações incluem:
9
+
10
+ - Versão do Python
11
+ - Instalação do mtcli
12
+ - Fonte de dados configurada
13
+ - Caminho de dados CSV
14
+ - Conexão com MetaTrader5
15
+ - Descoberta e carregamento de plugins
16
+
17
+ Caso algum plugin falhe ao carregar, o erro é exibido e registrado
18
+ no sistema de logs.
19
+ """
20
+
21
+ import sys
22
+ import click
23
+ import traceback
24
+
25
+ from importlib.metadata import version, PackageNotFoundError
26
+
27
+ import MetaTrader5 as mt5
28
+
29
+ from mtcli.logger import setup_logger
30
+ from mtcli.conf import conf, DATA_SOURCE_NAME
31
+ from mtcli.mt5_context import mt5_conexao
32
+ from mtcli.plugin_loader import discover_plugins
33
+
34
+
35
+ logger = setup_logger(__name__)
36
+
37
+
38
+ def status(ok: bool) -> str:
39
+ """
40
+ Retorna um marcador visual simples de status.
41
+
42
+ Parameters
43
+ ----------
44
+ ok : bool
45
+ Indica se o teste foi bem sucedido.
46
+
47
+ Returns
48
+ -------
49
+ str
50
+ Texto representando o status.
51
+ """
52
+ return "OK " if ok else "ERRO"
53
+
54
+
55
+ @click.command()
56
+ def doctor():
57
+ """
58
+ Executa diagnóstico do ambiente mtcli.
59
+
60
+ O comando verifica se os componentes essenciais do ambiente
61
+ estão funcionando corretamente e apresenta um relatório simples
62
+ no terminal.
63
+ """
64
+
65
+ click.echo("Diagnóstico do ambiente mtcli\n")
66
+
67
+ # ---------------------------------------------------------
68
+ # Python
69
+ # ---------------------------------------------------------
70
+
71
+ python_ok = sys.version_info >= (3, 10)
72
+
73
+ click.echo(f"{status(python_ok)} Python: {sys.version.split()[0]}")
74
+
75
+ if not python_ok:
76
+ click.echo(" Versão mínima recomendada: Python 3.10")
77
+
78
+ # ---------------------------------------------------------
79
+ # mtcli
80
+ # ---------------------------------------------------------
81
+
82
+ try:
83
+
84
+ mtcli_version = version("mtcli")
85
+
86
+ click.echo(f"{status(True)} mtcli: {mtcli_version}")
87
+
88
+ except PackageNotFoundError:
89
+
90
+ click.echo(f"{status(False)} mtcli não encontrado")
91
+
92
+ logger.error("Pacote mtcli não encontrado no ambiente.")
93
+
94
+ # ---------------------------------------------------------
95
+ # Fonte de dados
96
+ # ---------------------------------------------------------
97
+
98
+ click.echo(f"{status(True)} Data source: {DATA_SOURCE_NAME}")
99
+
100
+ # ---------------------------------------------------------
101
+ # CSV path
102
+ # ---------------------------------------------------------
103
+
104
+ try:
105
+
106
+ path = conf.get_csv_path()
107
+
108
+ click.echo(f"{status(True)} CSV path: {path}")
109
+
110
+ except Exception as exc:
111
+
112
+ click.echo(f"{status(False)} CSV path inválido")
113
+
114
+ logger.exception("Erro ao obter CSV path: %s", exc)
115
+
116
+ # ---------------------------------------------------------
117
+ # MT5 conexão
118
+ # ---------------------------------------------------------
119
+
120
+ try:
121
+
122
+ with mt5_conexao():
123
+
124
+ info = mt5.terminal_info()
125
+
126
+ if info:
127
+
128
+ click.echo(f"{status(True)} MetaTrader5 conectado")
129
+
130
+ else:
131
+
132
+ click.echo(f"{status(False)} MetaTrader5 não respondeu")
133
+
134
+ except Exception as exc:
135
+
136
+ click.echo(f"{status(False)} Falha na conexão MT5")
137
+
138
+ logger.exception("Erro ao conectar MT5: %s", exc)
139
+
140
+ # ---------------------------------------------------------
141
+ # Plugins
142
+ # ---------------------------------------------------------
143
+
144
+ click.echo("\nPlugins:")
145
+
146
+ try:
147
+
148
+ entry_points = list(discover_plugins())
149
+
150
+ if not entry_points:
151
+
152
+ click.echo(" Nenhum plugin encontrado.")
153
+ return
154
+
155
+ ok_count = 0
156
+ fail_count = 0
157
+
158
+ for ep in entry_points:
159
+
160
+ plugin_name = ep.name
161
+
162
+ try:
163
+
164
+ ep.load()
165
+
166
+ click.echo(f" OK {plugin_name}")
167
+
168
+ ok_count += 1
169
+
170
+ except Exception as exc:
171
+
172
+ click.echo(f" ERRO {plugin_name}")
173
+
174
+ click.echo(f" {exc}")
175
+
176
+ logger.error(
177
+ "Erro ao carregar plugin %s\n%s",
178
+ plugin_name,
179
+ traceback.format_exc(),
180
+ )
181
+
182
+ fail_count += 1
183
+
184
+ click.echo(
185
+ f"\nResumo: {ok_count} plugins OK | {fail_count} com erro"
186
+ )
187
+
188
+ except Exception as exc:
189
+
190
+ click.echo(f"{status(False)} Falha ao descobrir plugins")
191
+
192
+ logger.exception("Erro ao descobrir plugins: %s", exc)
193
+
194
+ click.echo("\nDiagnóstico concluído.")
@@ -0,0 +1,309 @@
1
+ """
2
+ Sistema central de configuração do mtcli.
3
+
4
+ Fornece leitura de configuração a partir de:
5
+
6
+ 1. Variáveis de ambiente
7
+ 2. Arquivo mtcli.ini
8
+ 3. Valores default
9
+
10
+ Também oferece utilidades usadas por plugins como:
11
+
12
+ - descoberta do diretório MQL5/Files
13
+ - seleção da fonte de dados (CSV ou MT5)
14
+
15
+ Plugins novos devem acessar a configuração através do objeto global `conf`.
16
+
17
+ Compatibilidade retroativa:
18
+ ---------------------------
19
+ Plugins antigos utilizavam:
20
+
21
+ from mtcli.conf import config
22
+
23
+ onde `config` era um objeto `configparser.ConfigParser`.
24
+
25
+ Para manter compatibilidade com plugins já publicados,
26
+ o objeto `config` continua sendo exposto.
27
+
28
+ Essa API é considerada **deprecated** e poderá ser removida
29
+ em versões futuras do mtcli.
30
+ """
31
+
32
+ import os
33
+ import configparser
34
+
35
+ import MetaTrader5 as mt5
36
+
37
+ from mtcli.mt5_context import mt5_conexao
38
+
39
+
40
+ class Config:
41
+ """
42
+ Gerenciador central de configurações do mtcli.
43
+
44
+ Permite acessar valores a partir de:
45
+
46
+ - variáveis de ambiente
47
+ - arquivo mtcli.ini
48
+ - valores default
49
+
50
+ Plugins devem preferencialmente usar:
51
+
52
+ from mtcli.conf import conf
53
+ conf.get(...)
54
+ """
55
+
56
+ def __init__(self, filename="mtcli.ini"):
57
+ self.config = configparser.ConfigParser()
58
+ self.config.read(filename)
59
+
60
+ # ---------------------------------------------------------
61
+ # leitura de valores
62
+ # ---------------------------------------------------------
63
+
64
+ def get(self, key, section="DEFAULT", cast=None, default=None):
65
+ """
66
+ Retorna um valor de configuração.
67
+
68
+ Prioridade:
69
+
70
+ 1. Variável de ambiente SECTION_KEY
71
+ 2. Variável de ambiente KEY
72
+ 3. mtcli.ini [section]
73
+ 4. mtcli.ini [DEFAULT]
74
+ 5. default
75
+
76
+ Args:
77
+ key (str):
78
+ Nome da configuração.
79
+
80
+ section (str):
81
+ Seção do arquivo mtcli.ini.
82
+
83
+ cast (type | None):
84
+ Tipo para conversão do valor.
85
+
86
+ default (Any):
87
+ Valor padrão.
88
+
89
+ Returns:
90
+ Any
91
+ """
92
+
93
+ env_key = f"{section.upper()}_{key.upper()}"
94
+
95
+ value = os.getenv(env_key) or os.getenv(key.upper())
96
+
97
+ if value is None:
98
+
99
+ if self.config.has_option(section, key):
100
+ value = self.config.get(section, key)
101
+
102
+ elif self.config.has_option("DEFAULT", key):
103
+ value = self.config.get("DEFAULT", key)
104
+
105
+ else:
106
+ value = default
107
+
108
+ if cast and value is not None:
109
+
110
+ try:
111
+
112
+ if cast is bool:
113
+ value = str(value).lower() in ("1", "true", "yes")
114
+
115
+ else:
116
+ value = cast(value)
117
+
118
+ except ValueError:
119
+ value = default
120
+
121
+ return value
122
+
123
+ # ---------------------------------------------------------
124
+ # seção helper
125
+ # ---------------------------------------------------------
126
+
127
+ def section(self, section):
128
+ """
129
+ Retorna um helper para acessar uma seção específica.
130
+
131
+ Example:
132
+
133
+ renko = conf.section("renko")
134
+ brick = renko.get("brick", cast=int, default=10)
135
+ """
136
+
137
+ class Section:
138
+ def __init__(self, parent, section):
139
+ self.parent = parent
140
+ self.section = section
141
+
142
+ def get(self, key, cast=None, default=None):
143
+ return self.parent.get(key, self.section, cast, default)
144
+
145
+ return Section(self, section)
146
+
147
+ # ---------------------------------------------------------
148
+ # caminho MT5
149
+ # ---------------------------------------------------------
150
+
151
+ def get_csv_path(self):
152
+ """
153
+ Retorna o caminho da pasta MQL5/Files do MetaTrader 5.
154
+
155
+ A prioridade é:
156
+
157
+ 1. mtcli.ini -> mt5_pasta
158
+ 2. descoberta automática via MT5
159
+
160
+ Returns:
161
+ str: caminho normalizado da pasta Files.
162
+ """
163
+
164
+ path = self.get("mt5_pasta")
165
+
166
+ if path:
167
+ return os.path.normpath(path) + os.sep
168
+
169
+ with mt5_conexao():
170
+
171
+ info = mt5.terminal_info()
172
+
173
+ if info is None:
174
+ raise RuntimeError(
175
+ "Não foi possível obter informações do terminal MT5."
176
+ )
177
+
178
+ path = os.path.join(info.data_path, "MQL5", "Files")
179
+
180
+ return os.path.normpath(path) + os.sep
181
+
182
+ # ---------------------------------------------------------
183
+ # data source
184
+ # ---------------------------------------------------------
185
+
186
+ def get_data_source(self, source=None):
187
+ """
188
+ Retorna a fonte de dados configurada.
189
+
190
+ Args:
191
+ source (str | None):
192
+ Fonte explícita ("csv" ou "mt5").
193
+
194
+ Returns:
195
+ DataSource
196
+ """
197
+
198
+ from mtcli.data import CsvDataSource, MT5DataSource
199
+
200
+ src = (source or self.get("dados", default="mt5")).lower()
201
+
202
+ if src == "csv":
203
+ return CsvDataSource()
204
+
205
+ if src == "mt5":
206
+ return MT5DataSource()
207
+
208
+ raise ValueError(f"Fonte de dados desconhecida: {src}")
209
+
210
+
211
+ # ---------------------------------------------------------
212
+ # instância global usada por todo o sistema
213
+ # ---------------------------------------------------------
214
+
215
+ conf = Config()
216
+
217
+ # ---------------------------------------------------------
218
+ # compatibilidade com plugins antigos
219
+ # ---------------------------------------------------------
220
+ #
221
+ # Plugins antigos utilizam:
222
+ #
223
+ # from mtcli.conf import config
224
+ #
225
+ # onde `config` era um ConfigParser.
226
+ #
227
+ # Mantemos esse objeto apontando para o ConfigParser interno
228
+ # para evitar quebra de compatibilidade.
229
+ #
230
+ # API DEPRECATED – usar `conf.get()` em novos plugins.
231
+ #
232
+
233
+ config = conf.config
234
+
235
+
236
+ # ---------------------------------------------------------
237
+ # timeframes suportados
238
+ # ---------------------------------------------------------
239
+
240
+ _HOURS = [12, 8, 6, 4, 3, 2, 1]
241
+ _MINUTES = [30, 20, 15, 12, 10, 6, 5, 4, 3, 2, 1]
242
+
243
+ TIMEFRAMES = (
244
+ ["mn1", "w1", "d1"]
245
+ + [f"h{i}" for i in _HOURS]
246
+ + [f"m{i}" for i in _MINUTES]
247
+ )
248
+
249
+ # ---------------------------------------------------------
250
+ # Configurações gerais
251
+ # ---------------------------------------------------------
252
+
253
+ SYMBOL = conf.get("symbol", default="WIN$N")
254
+ DIGITOS = conf.get("digitos", cast=int, default=2)
255
+ PERIOD = conf.get("period", default="D1")
256
+ BARS = conf.get("count", cast=int, default=999)
257
+
258
+ VIEW = conf.get("view", default="ch")
259
+ VOLUME = conf.get("volume", default="tick")
260
+ DATE = conf.get("date", default="")
261
+
262
+ # ---------------------------------------------------------
263
+ # Configurações de leitura de candles
264
+ # ---------------------------------------------------------
265
+
266
+ LATERAL = conf.get("lateral", default="doji")
267
+ ALTA = conf.get("alta", default="verde")
268
+ BAIXA = conf.get("baixa", default="vermelho")
269
+
270
+ ROMPIMENTO_ALTA = conf.get("rompimento_alta", default="c")
271
+ ROMPIMENTO_BAIXA = conf.get("rompimento_baixa", default="v")
272
+
273
+ PERCENTUAL_ROMPIMENTO = conf.get(
274
+ "percentual_rompimento",
275
+ cast=int,
276
+ default=50,
277
+ )
278
+
279
+ PERCENTUAL_DOJI = conf.get(
280
+ "percentual_doji",
281
+ cast=int,
282
+ default=10,
283
+ )
284
+
285
+ # ---------------------------------------------------------
286
+ # Configurações de padrões de barra
287
+ # ---------------------------------------------------------
288
+
289
+ UP_BAR = conf.get("up_bar", default="asc")
290
+ DOWN_BAR = conf.get("down_bar", default="desc")
291
+
292
+ INSIDE_BAR = conf.get("inside_bar", default="ib")
293
+ OUTSIDE_BAR = conf.get("outside_bar", default="ob")
294
+
295
+ SOMBRA_SUPERIOR = conf.get("sombra_superior", default="top")
296
+ SOMBRA_INFERIOR = conf.get("sombra_inferior", default="bottom")
297
+
298
+ # ---------------------------------------------------------
299
+ # Fonte de dados
300
+ # ---------------------------------------------------------
301
+
302
+ DATA_SOURCE_NAME = conf.get("dados", default="mt5").lower()
303
+ DATA_SOURCE = conf.get_data_source()
304
+
305
+ # ---------------------------------------------------------
306
+ # caminho inicial do CSV (pode vir do ini/env)
307
+ # ---------------------------------------------------------
308
+
309
+ _INITIAL_CSV_PATH = conf.get_csv_path()
@@ -0,0 +1,41 @@
1
+ """
2
+ Registry de configurações do mtcli.
3
+
4
+ Plugins podem registrar suas opções de configuração aqui
5
+ para permitir descoberta automática via CLI.
6
+ """
7
+
8
+
9
+ class ConfigOption:
10
+ """
11
+ Representa uma opção de configuração registrada.
12
+ """
13
+
14
+ def __init__(self, section, name, type=str, default=None, description=""):
15
+ self.section = section
16
+ self.name = name
17
+ self.type = type
18
+ self.default = default
19
+ self.description = description
20
+
21
+
22
+ class ConfigRegistry:
23
+ """
24
+ Registro central de opções de configuração.
25
+ """
26
+
27
+ def __init__(self):
28
+ self._options = []
29
+
30
+ def register(self, section, name, type=str, default=None, description=""):
31
+ option = ConfigOption(section, name, type, default, description)
32
+ self._options.append(option)
33
+
34
+ def get_all(self):
35
+ return self._options
36
+
37
+ def get_section(self, section):
38
+ return [o for o in self._options if o.section == section]
39
+
40
+
41
+ registry = ConfigRegistry()