mtcli 3.0.0.dev2__tar.gz → 3.2.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.
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/PKG-INFO +1 -1
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/commands/conf.py +50 -50
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/conf.py +101 -101
- mtcli-3.2.0.dev0/mtcli/logger.py +45 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/conf_model.py +33 -33
- mtcli-3.2.0.dev0/mtcli/mt5_context.py +33 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/pyproject.toml +1 -1
- mtcli-3.0.0.dev2/mtcli/logger.py +0 -29
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/LICENSE +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/README.md +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/commands/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/commands/bars.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/commands/logs.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/conecta.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/data/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/data/base.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/data/csv.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/data/mt5.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/bar_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/bars_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/chart_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/consecutive_bars_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/rates_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/signals_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/models/unconsecutive_bar_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/mt.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugin.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/agressao/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/agressao/command.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/agressao/conf.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/agressao/models/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/agressao/models/model_agressao.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/agressao/views/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/agressao/views/view_agressao.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/command.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/conf.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/models/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/models/model_media_movel.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/tests/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/tests/test_mm.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/tests/test_model_media_movel.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/command.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/conf.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/models/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/models/average_range_model.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/tests/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/tests/test_rm.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/command.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/conf.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/models/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/models/model_average_volume.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/tests/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/tests/test_vm.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/__init__.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/close_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/full_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/high_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/low_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/min_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/open_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/ranges_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/rates_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/vars_view.py +0 -0
- {mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/views/volumes_view.py +0 -0
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
"""Gerencia configurações registradas no mtcli.ini."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import click
|
|
5
|
-
from mtcli.models.conf_model import ConfModel
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@click.command(
|
|
9
|
-
"conf",
|
|
10
|
-
help="Gerencia as configurações salvas no arquivo mtcli.ini (adicionar, editar, listar).",
|
|
11
|
-
)
|
|
12
|
-
@click.option("--list", "list_", is_flag=True, help="Lista todas as configurações.")
|
|
13
|
-
@click.option("--set", "set_", nargs=2, help="Define o valor de uma configuração.")
|
|
14
|
-
@click.option("--get", help="Exibe o valor de uma configuração.")
|
|
15
|
-
@click.option("--reset", is_flag=True, help="Redefine as configurações padrão.")
|
|
16
|
-
def conf(list_, set_, get, reset):
|
|
17
|
-
"""Gerencia configurações registradas no mtcli.ini."""
|
|
18
|
-
conf = ConfModel("mtcli.ini")
|
|
19
|
-
config = conf.carregar()
|
|
20
|
-
|
|
21
|
-
if list_:
|
|
22
|
-
for key in config["DEFAULT"]:
|
|
23
|
-
click.echo(f"{key} = {config['DEFAULT'][key]}")
|
|
24
|
-
|
|
25
|
-
elif set_:
|
|
26
|
-
chave, valor = set_
|
|
27
|
-
config["DEFAULT"][chave] = valor
|
|
28
|
-
conf.salvar(config)
|
|
29
|
-
click.echo(f"Configuração '{chave}' definida como '{valor}'.")
|
|
30
|
-
|
|
31
|
-
elif get:
|
|
32
|
-
valor = config["DEFAULT"].get(get)
|
|
33
|
-
if valor is not None:
|
|
34
|
-
click.echo(f"{get} = {valor}")
|
|
35
|
-
else:
|
|
36
|
-
click.echo(f"Configuração '{get}' não encontrada.")
|
|
37
|
-
|
|
38
|
-
elif reset:
|
|
39
|
-
config["DEFAULT"].clear()
|
|
40
|
-
conf.salvar(config)
|
|
41
|
-
click.echo("Configurações redefinidas.")
|
|
42
|
-
|
|
43
|
-
else:
|
|
44
|
-
click.echo(
|
|
45
|
-
"Nenhuma opção fornecida. Use --help para ver as opções disponíveis."
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if __name__ == "__main__":
|
|
50
|
-
conf()
|
|
1
|
+
"""Gerencia configurações registradas no mtcli.ini."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import click
|
|
5
|
+
from mtcli.models.conf_model import ConfModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.command(
|
|
9
|
+
"conf",
|
|
10
|
+
help="Gerencia as configurações salvas no arquivo mtcli.ini (adicionar, editar, listar).",
|
|
11
|
+
)
|
|
12
|
+
@click.option("--list", "list_", is_flag=True, help="Lista todas as configurações.")
|
|
13
|
+
@click.option("--set", "set_", nargs=2, help="Define o valor de uma configuração.")
|
|
14
|
+
@click.option("--get", help="Exibe o valor de uma configuração.")
|
|
15
|
+
@click.option("--reset", is_flag=True, help="Redefine as configurações padrão.")
|
|
16
|
+
def conf(list_, set_, get, reset):
|
|
17
|
+
"""Gerencia configurações registradas no mtcli.ini."""
|
|
18
|
+
conf = ConfModel("mtcli.ini")
|
|
19
|
+
config = conf.carregar()
|
|
20
|
+
|
|
21
|
+
if list_:
|
|
22
|
+
for key in config["DEFAULT"]:
|
|
23
|
+
click.echo(f"{key} = {config['DEFAULT'][key]}")
|
|
24
|
+
|
|
25
|
+
elif set_:
|
|
26
|
+
chave, valor = set_
|
|
27
|
+
config["DEFAULT"][chave] = valor
|
|
28
|
+
conf.salvar(config)
|
|
29
|
+
click.echo(f"Configuração '{chave}' definida como '{valor}'.")
|
|
30
|
+
|
|
31
|
+
elif get:
|
|
32
|
+
valor = config["DEFAULT"].get(get)
|
|
33
|
+
if valor is not None:
|
|
34
|
+
click.echo(f"{get} = {valor}")
|
|
35
|
+
else:
|
|
36
|
+
click.echo(f"Configuração '{get}' não encontrada.")
|
|
37
|
+
|
|
38
|
+
elif reset:
|
|
39
|
+
config["DEFAULT"].clear()
|
|
40
|
+
conf.salvar(config)
|
|
41
|
+
click.echo("Configurações redefinidas.")
|
|
42
|
+
|
|
43
|
+
else:
|
|
44
|
+
click.echo(
|
|
45
|
+
"Nenhuma opção fornecida. Use --help para ver as opções disponíveis."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
conf()
|
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import MetaTrader5 as mt5
|
|
3
|
-
from mtcli.conecta import conectar, shutdown
|
|
4
|
-
from mtcli.models.conf_model import ConfModel
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
config = ConfModel("mtcli.ini").carregar()
|
|
8
|
-
|
|
9
|
-
section = "DEFAULT"
|
|
10
|
-
symbol = os.getenv("SYMBOL", config[section].get("symbol", fallback="WIN$N"))
|
|
11
|
-
digitos = int(os.getenv("DIGITOS", config[section].getint("digitos", fallback=2)))
|
|
12
|
-
period = os.getenv("PERIOD", config[section].get("period", fallback="D1"))
|
|
13
|
-
periodos = count = int(
|
|
14
|
-
os.getenv("COUNT", config[section].getint("count", fallback=999))
|
|
15
|
-
)
|
|
16
|
-
view = os.getenv("VIEW", config[section].get("view", fallback="ch"))
|
|
17
|
-
volume = os.getenv("VOLUME", config[section].get("volume", fallback="tick"))
|
|
18
|
-
date = os.getenv("DATE", config[section].get("date", fallback=""))
|
|
19
|
-
|
|
20
|
-
lateral = os.getenv("LATERAL", config[section].get("lateral", fallback="doji"))
|
|
21
|
-
alta = os.getenv("ALTA", config[section].get("alta", fallback="verde"))
|
|
22
|
-
baixa = os.getenv("BAIXA", config[section].get("baixa", fallback="vermelho"))
|
|
23
|
-
rompimento_alta = os.getenv(
|
|
24
|
-
"ROMPIMENTO_ALTA", config[section].get("rompimento_alta", fallback="c")
|
|
25
|
-
)
|
|
26
|
-
rompimento_baixa = os.getenv(
|
|
27
|
-
"ROMPIMENTO_BAIXA", config[section].get("rompimento_baixa", fallback="v")
|
|
28
|
-
)
|
|
29
|
-
percentual_rompimento = int(
|
|
30
|
-
os.getenv(
|
|
31
|
-
"PERCENTUAL_ROMPIMENTO",
|
|
32
|
-
config[section].getint("percentual_rompimento", fallback=50),
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
percentual_doji = int(
|
|
36
|
-
os.getenv("PERCENTUAL_DOJI", config[section].getint("percentual_doji", fallback=10))
|
|
37
|
-
)
|
|
38
|
-
up_bar = os.getenv("UP_BAR", config[section].get("up_bar", fallback="asc"))
|
|
39
|
-
down_bar = os.getenv("DOWN_BAR", config[section].get("down_bar", fallback="desc"))
|
|
40
|
-
inside_bar = os.getenv("INSIDE_BAR", config[section].get("inside_bar", fallback="ib"))
|
|
41
|
-
outside_bar = os.getenv(
|
|
42
|
-
"OUTSIDE_BAR", config[section].get("outside_bar", fallback="ob")
|
|
43
|
-
)
|
|
44
|
-
sombra_superior = os.getenv(
|
|
45
|
-
"SOMBRA_SUPERIOR", config[section].get("sombra_superior", fallback="top")
|
|
46
|
-
)
|
|
47
|
-
sombra_inferior = os.getenv(
|
|
48
|
-
"SOMBRA_INFERIOR", config[section].get("sombra_inferior", fallback="bottom")
|
|
49
|
-
)
|
|
50
|
-
data_source = dados = os.getenv("DADOS", config[section].get("dados", fallback="mt5"))
|
|
51
|
-
csv_path = mt5_pasta = os.getenv(
|
|
52
|
-
"MT5_PASTA", config[section].get("mt5_pasta", fallback="")
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def get_data_source():
|
|
57
|
-
from mtcli.data import CsvDataSource, MT5DataSource
|
|
58
|
-
|
|
59
|
-
if data_source.lower() == "csv":
|
|
60
|
-
return CsvDataSource()
|
|
61
|
-
elif data_source.lower() == "mt5":
|
|
62
|
-
return MT5DataSource()
|
|
63
|
-
else:
|
|
64
|
-
raise ValueError(f"Fonte de dados desconhecida: {data_source}")
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if not csv_path:
|
|
68
|
-
conectar()
|
|
69
|
-
terminal_info = mt5.terminal_info()
|
|
70
|
-
if terminal_info is None:
|
|
71
|
-
raise RuntimeError("Não foi possível obter as informações do terminal.")
|
|
72
|
-
|
|
73
|
-
csv_path = terminal_info.data_path + "/MQL5/Files"
|
|
74
|
-
shutdown()
|
|
75
|
-
|
|
76
|
-
csv_path = csv_path.replace("\\", "/")
|
|
77
|
-
csv_path += "/"
|
|
78
|
-
|
|
79
|
-
timeframes = [
|
|
80
|
-
"mn1",
|
|
81
|
-
"w1",
|
|
82
|
-
"d1",
|
|
83
|
-
"h12",
|
|
84
|
-
"h8",
|
|
85
|
-
"h6",
|
|
86
|
-
"h4",
|
|
87
|
-
"h3",
|
|
88
|
-
"h2",
|
|
89
|
-
"h1",
|
|
90
|
-
"m30",
|
|
91
|
-
"m20",
|
|
92
|
-
"m15",
|
|
93
|
-
"m12",
|
|
94
|
-
"m10",
|
|
95
|
-
"m6",
|
|
96
|
-
"m5",
|
|
97
|
-
"m4",
|
|
98
|
-
"m3",
|
|
99
|
-
"m2",
|
|
100
|
-
"m1",
|
|
101
|
-
]
|
|
1
|
+
import os
|
|
2
|
+
import MetaTrader5 as mt5
|
|
3
|
+
from mtcli.conecta import conectar, shutdown
|
|
4
|
+
from mtcli.models.conf_model import ConfModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
config = ConfModel("mtcli.ini").carregar()
|
|
8
|
+
|
|
9
|
+
section = "DEFAULT"
|
|
10
|
+
symbol = os.getenv("SYMBOL", config[section].get("symbol", fallback="WIN$N"))
|
|
11
|
+
digitos = int(os.getenv("DIGITOS", config[section].getint("digitos", fallback=2)))
|
|
12
|
+
period = os.getenv("PERIOD", config[section].get("period", fallback="D1"))
|
|
13
|
+
periodos = count = int(
|
|
14
|
+
os.getenv("COUNT", config[section].getint("count", fallback=999))
|
|
15
|
+
)
|
|
16
|
+
view = os.getenv("VIEW", config[section].get("view", fallback="ch"))
|
|
17
|
+
volume = os.getenv("VOLUME", config[section].get("volume", fallback="tick"))
|
|
18
|
+
date = os.getenv("DATE", config[section].get("date", fallback=""))
|
|
19
|
+
|
|
20
|
+
lateral = os.getenv("LATERAL", config[section].get("lateral", fallback="doji"))
|
|
21
|
+
alta = os.getenv("ALTA", config[section].get("alta", fallback="verde"))
|
|
22
|
+
baixa = os.getenv("BAIXA", config[section].get("baixa", fallback="vermelho"))
|
|
23
|
+
rompimento_alta = os.getenv(
|
|
24
|
+
"ROMPIMENTO_ALTA", config[section].get("rompimento_alta", fallback="c")
|
|
25
|
+
)
|
|
26
|
+
rompimento_baixa = os.getenv(
|
|
27
|
+
"ROMPIMENTO_BAIXA", config[section].get("rompimento_baixa", fallback="v")
|
|
28
|
+
)
|
|
29
|
+
percentual_rompimento = int(
|
|
30
|
+
os.getenv(
|
|
31
|
+
"PERCENTUAL_ROMPIMENTO",
|
|
32
|
+
config[section].getint("percentual_rompimento", fallback=50),
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
percentual_doji = int(
|
|
36
|
+
os.getenv("PERCENTUAL_DOJI", config[section].getint("percentual_doji", fallback=10))
|
|
37
|
+
)
|
|
38
|
+
up_bar = os.getenv("UP_BAR", config[section].get("up_bar", fallback="asc"))
|
|
39
|
+
down_bar = os.getenv("DOWN_BAR", config[section].get("down_bar", fallback="desc"))
|
|
40
|
+
inside_bar = os.getenv("INSIDE_BAR", config[section].get("inside_bar", fallback="ib"))
|
|
41
|
+
outside_bar = os.getenv(
|
|
42
|
+
"OUTSIDE_BAR", config[section].get("outside_bar", fallback="ob")
|
|
43
|
+
)
|
|
44
|
+
sombra_superior = os.getenv(
|
|
45
|
+
"SOMBRA_SUPERIOR", config[section].get("sombra_superior", fallback="top")
|
|
46
|
+
)
|
|
47
|
+
sombra_inferior = os.getenv(
|
|
48
|
+
"SOMBRA_INFERIOR", config[section].get("sombra_inferior", fallback="bottom")
|
|
49
|
+
)
|
|
50
|
+
data_source = dados = os.getenv("DADOS", config[section].get("dados", fallback="mt5"))
|
|
51
|
+
csv_path = mt5_pasta = os.getenv(
|
|
52
|
+
"MT5_PASTA", config[section].get("mt5_pasta", fallback="")
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_data_source():
|
|
57
|
+
from mtcli.data import CsvDataSource, MT5DataSource
|
|
58
|
+
|
|
59
|
+
if data_source.lower() == "csv":
|
|
60
|
+
return CsvDataSource()
|
|
61
|
+
elif data_source.lower() == "mt5":
|
|
62
|
+
return MT5DataSource()
|
|
63
|
+
else:
|
|
64
|
+
raise ValueError(f"Fonte de dados desconhecida: {data_source}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if not csv_path:
|
|
68
|
+
conectar()
|
|
69
|
+
terminal_info = mt5.terminal_info()
|
|
70
|
+
if terminal_info is None:
|
|
71
|
+
raise RuntimeError("Não foi possível obter as informações do terminal.")
|
|
72
|
+
|
|
73
|
+
csv_path = terminal_info.data_path + "/MQL5/Files"
|
|
74
|
+
shutdown()
|
|
75
|
+
|
|
76
|
+
csv_path = csv_path.replace("\\", "/")
|
|
77
|
+
csv_path += "/"
|
|
78
|
+
|
|
79
|
+
timeframes = [
|
|
80
|
+
"mn1",
|
|
81
|
+
"w1",
|
|
82
|
+
"d1",
|
|
83
|
+
"h12",
|
|
84
|
+
"h8",
|
|
85
|
+
"h6",
|
|
86
|
+
"h4",
|
|
87
|
+
"h3",
|
|
88
|
+
"h2",
|
|
89
|
+
"h1",
|
|
90
|
+
"m30",
|
|
91
|
+
"m20",
|
|
92
|
+
"m15",
|
|
93
|
+
"m12",
|
|
94
|
+
"m10",
|
|
95
|
+
"m6",
|
|
96
|
+
"m5",
|
|
97
|
+
"m4",
|
|
98
|
+
"m3",
|
|
99
|
+
"m2",
|
|
100
|
+
"m1",
|
|
101
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from logging.handlers import RotatingFileHandler
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
LOG_DIR = os.path.join(os.path.expanduser("~"), ".mtcli")
|
|
6
|
+
os.makedirs(LOG_DIR, exist_ok=True)
|
|
7
|
+
LOG_FILE = os.path.join(LOG_DIR, "mtcli.log")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def setup_logger(name: str = "mtcli") -> logging.Logger:
|
|
11
|
+
"""Configura logger rotativo com saída em arquivo e console.
|
|
12
|
+
|
|
13
|
+
- Escreve logs em ~/.mtcli/mtcli.log (máx. 2 MB, 3 backups).
|
|
14
|
+
- Mostra logs também no console (stdout), capturáveis via pytest/caplog.
|
|
15
|
+
- Evita duplicar handlers.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(name)
|
|
19
|
+
logger.setLevel(logging.DEBUG)
|
|
20
|
+
|
|
21
|
+
formatter = logging.Formatter(
|
|
22
|
+
"%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
|
|
23
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# === File handler rotativo ===
|
|
27
|
+
if not any(isinstance(h, RotatingFileHandler) for h in logger.handlers):
|
|
28
|
+
file_handler = RotatingFileHandler(LOG_FILE, maxBytes=2_000_000, backupCount=3)
|
|
29
|
+
file_handler.setFormatter(formatter)
|
|
30
|
+
logger.addHandler(file_handler)
|
|
31
|
+
|
|
32
|
+
# === Stream handler (console) ===
|
|
33
|
+
if not any(isinstance(h, logging.StreamHandler) for h in logger.handlers):
|
|
34
|
+
console_handler = logging.StreamHandler()
|
|
35
|
+
console_handler.setFormatter(formatter)
|
|
36
|
+
logger.addHandler(console_handler)
|
|
37
|
+
|
|
38
|
+
# Permite que pytest caplog capture logs
|
|
39
|
+
logger.propagate = True
|
|
40
|
+
|
|
41
|
+
return logger
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Inicializa logger padrão
|
|
45
|
+
log = setup_logger()
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
"""Modelo de configurações."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import configparser
|
|
5
|
-
from configparser import MissingSectionHeaderError
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ConfigFormatError(Exception):
|
|
9
|
-
pass
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ConfModel:
|
|
13
|
-
|
|
14
|
-
def __init__(self, configuracoes):
|
|
15
|
-
self.CONFIG_PATH = os.path.abspath(configuracoes)
|
|
16
|
-
|
|
17
|
-
def carregar(self):
|
|
18
|
-
config = configparser.ConfigParser()
|
|
19
|
-
if os.path.exists(self.CONFIG_PATH):
|
|
20
|
-
try:
|
|
21
|
-
config.read(self.CONFIG_PATH)
|
|
22
|
-
except MissingSectionHeaderError:
|
|
23
|
-
raise ConfigFormatError(
|
|
24
|
-
f"Erro: o arquivo '{self.CONFIG_PATH}' não contém seções válidas.\n"
|
|
25
|
-
"Certifique-se de que ele está no formato correto:\n[padrao]\nCHAVE=valor"
|
|
26
|
-
)
|
|
27
|
-
else:
|
|
28
|
-
config["DEFAULT"] = {}
|
|
29
|
-
return config
|
|
30
|
-
|
|
31
|
-
def salvar(self, config):
|
|
32
|
-
with open(self.CONFIG_PATH, "w") as f:
|
|
33
|
-
config.write(f)
|
|
1
|
+
"""Modelo de configurações."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import configparser
|
|
5
|
+
from configparser import MissingSectionHeaderError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ConfigFormatError(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ConfModel:
|
|
13
|
+
|
|
14
|
+
def __init__(self, configuracoes):
|
|
15
|
+
self.CONFIG_PATH = os.path.abspath(configuracoes)
|
|
16
|
+
|
|
17
|
+
def carregar(self):
|
|
18
|
+
config = configparser.ConfigParser()
|
|
19
|
+
if os.path.exists(self.CONFIG_PATH):
|
|
20
|
+
try:
|
|
21
|
+
config.read(self.CONFIG_PATH)
|
|
22
|
+
except MissingSectionHeaderError:
|
|
23
|
+
raise ConfigFormatError(
|
|
24
|
+
f"Erro: o arquivo '{self.CONFIG_PATH}' não contém seções válidas.\n"
|
|
25
|
+
"Certifique-se de que ele está no formato correto:\n[padrao]\nCHAVE=valor"
|
|
26
|
+
)
|
|
27
|
+
else:
|
|
28
|
+
config["DEFAULT"] = {}
|
|
29
|
+
return config
|
|
30
|
+
|
|
31
|
+
def salvar(self, config):
|
|
32
|
+
with open(self.CONFIG_PATH, "w") as f:
|
|
33
|
+
config.write(f)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Gerencia o ciclo de conexão com o MetaTrader 5.
|
|
3
|
+
Fornece o contexto 'mt5_conexao' para uso seguro em blocos with.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from mtcli.logger import setup_logger
|
|
8
|
+
from mtcli.conecta import conectar, shutdown
|
|
9
|
+
|
|
10
|
+
log = setup_logger()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@contextmanager
|
|
14
|
+
def mt5_conexao():
|
|
15
|
+
"""
|
|
16
|
+
Context manager para conexão com o MetaTrader 5.
|
|
17
|
+
- Chama `conectar()` ao entrar no contexto.
|
|
18
|
+
- Chama `shutdown()` ao sair.
|
|
19
|
+
- Loga falhas e garante fechamento seguro.
|
|
20
|
+
"""
|
|
21
|
+
try:
|
|
22
|
+
log.debug("Inicializando conexão com MetaTrader 5...")
|
|
23
|
+
conectar()
|
|
24
|
+
yield
|
|
25
|
+
except Exception as e:
|
|
26
|
+
log.error(f"Erro ao conectar ao MetaTrader 5: {e}")
|
|
27
|
+
raise
|
|
28
|
+
finally:
|
|
29
|
+
try:
|
|
30
|
+
shutdown()
|
|
31
|
+
log.debug("Conexão com MetaTrader 5 encerrada.")
|
|
32
|
+
except Exception as e:
|
|
33
|
+
log.error(f"Erro ao encerrar conexão MT5: {e}")
|
mtcli-3.0.0.dev2/mtcli/logger.py
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"""Módulo de logging."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import logging
|
|
5
|
-
from logging.handlers import RotatingFileHandler
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def setup_logger(name="mtcli"):
|
|
9
|
-
if os.name == "nt":
|
|
10
|
-
base_dir = os.getenv("APPDATA", os.path.expanduser("~"))
|
|
11
|
-
log_dir = os.path.join(base_dir, name, "logs")
|
|
12
|
-
else:
|
|
13
|
-
base_dir = os.path.expanduser("~/.local/share")
|
|
14
|
-
log_dir = os.path.join(base_dir, name, "logs")
|
|
15
|
-
|
|
16
|
-
os.makedirs(log_dir, exist_ok=True)
|
|
17
|
-
log_path = os.path.join(log_dir, f"{name}.log")
|
|
18
|
-
|
|
19
|
-
handler = RotatingFileHandler(log_path, maxBytes=1_000_000, backupCount=3)
|
|
20
|
-
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
|
21
|
-
handler.setFormatter(formatter)
|
|
22
|
-
|
|
23
|
-
logger = logging.getLogger(name)
|
|
24
|
-
logger.setLevel(logging.DEBUG)
|
|
25
|
-
if not logger.handlers:
|
|
26
|
-
logger.addHandler(handler)
|
|
27
|
-
logger.propagate = False
|
|
28
|
-
|
|
29
|
-
return logger
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/media_movel/tests/test_model_media_movel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/range_medio/models/average_range_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mtcli-3.0.0.dev2 → mtcli-3.2.0.dev0}/mtcli/plugins/volume_medio/models/model_average_volume.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|