mtcli 3.6.0.dev0__tar.gz → 3.6.0.dev1__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.6.0.dev0 → mtcli-3.6.0.dev1}/PKG-INFO +1 -1
- mtcli-3.6.0.dev1/mtcli/cli.py +34 -0
- mtcli-3.6.0.dev1/mtcli/plugin_loader.py +97 -0
- mtcli-3.6.0.dev1/mtcli/plugins/exemplo.py-dist +30 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/__init__.py +5 -5
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/cli.py +98 -98
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/pyproject.toml +1 -1
- mtcli-3.6.0.dev0/mtcli/cli.py +0 -32
- mtcli-3.6.0.dev0/mtcli/plugin_loader.py +0 -57
- mtcli-3.6.0.dev0/mtcli/plugins/hello.py +0 -20
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/LICENSE +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/README.md +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/commands/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/commands/bars.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/conecta.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/conf.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/data/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/data/base.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/data/csv.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/data/mt5.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/database.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/domain/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/domain/timeframe.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/logger.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/marketdata/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/marketdata/tick_cache.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/marketdata/tick_repository.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/bar_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/bars_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/chart_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/conf_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/consecutive_bars_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/rates_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/signals_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/models/unconsecutive_bar_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/mt5_context.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugin.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/conf.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/models/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/models/model_media_movel.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/tests/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/tests/test_mm.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/media_movel/tests/test_model_media_movel.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/range_medio/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/range_medio/cli.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/range_medio/conf.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/range_medio/models/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/range_medio/models/average_range_model.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/range_medio/tests/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/range_medio/tests/test_rm.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/volume_medio/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/volume_medio/cli.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/volume_medio/conf.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/volume_medio/models/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/volume_medio/models/model_average_volume.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/volume_medio/tests/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/plugins/volume_medio/tests/test_vm.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/__init__.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/close_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/full_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/high_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/low_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/min_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/open_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/ranges_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/rates_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/vars_view.py +0 -0
- {mtcli-3.6.0.dev0 → mtcli-3.6.0.dev1}/mtcli/views/volumes_view.py +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
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 .commands.bars import bars
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group(context_settings={"max_content_width": 120})
|
|
15
|
+
@click.version_option(package_name="mtcli")
|
|
16
|
+
def mt():
|
|
17
|
+
"""
|
|
18
|
+
CLI principal do mtcli.
|
|
19
|
+
|
|
20
|
+
Exibe gráficos e informações de mercado
|
|
21
|
+
em formato textual compatível com leitores de tela.
|
|
22
|
+
"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
mt.add_command(bars, name="bars")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Carrega plugins automaticamente
|
|
30
|
+
load_plugins(mt)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
mt()
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sistema de carregamento de plugins do mtcli.
|
|
3
|
+
|
|
4
|
+
Este módulo carrega automaticamente:
|
|
5
|
+
|
|
6
|
+
1. Plugins internos localizados em `mtcli.plugins`
|
|
7
|
+
2. Plugins externos registrados via entry points `mtcli.plugins`
|
|
8
|
+
|
|
9
|
+
Plugins devem expor uma função:
|
|
10
|
+
|
|
11
|
+
register(cli)
|
|
12
|
+
|
|
13
|
+
onde `cli` é o grupo principal do Click.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import importlib
|
|
17
|
+
import pkgutil
|
|
18
|
+
|
|
19
|
+
import click
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
from importlib.metadata import entry_points
|
|
23
|
+
except ImportError: # Python < 3.10
|
|
24
|
+
from importlib_metadata import entry_points
|
|
25
|
+
|
|
26
|
+
import mtcli.plugins
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def load_internal_plugins(cli: click.Group) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Carrega plugins internos do pacote `mtcli.plugins`.
|
|
32
|
+
|
|
33
|
+
Cada módulo encontrado deve expor a função:
|
|
34
|
+
|
|
35
|
+
register(cli)
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
cli: grupo principal do Click.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
for module_info in pkgutil.iter_modules(mtcli.plugins.__path__):
|
|
42
|
+
|
|
43
|
+
module_name = f"mtcli.plugins.{module_info.name}"
|
|
44
|
+
|
|
45
|
+
module = importlib.import_module(module_name)
|
|
46
|
+
|
|
47
|
+
if hasattr(module, "register"):
|
|
48
|
+
module.register(cli)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def load_external_plugins(cli: click.Group) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Carrega plugins externos instalados via entry points.
|
|
54
|
+
|
|
55
|
+
Os plugins devem declarar no pyproject.toml:
|
|
56
|
+
|
|
57
|
+
[project.entry-points."mtcli.plugins"]
|
|
58
|
+
nome = "pacote.plugin:register"
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
cli: grupo principal do Click.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
eps = entry_points()
|
|
65
|
+
|
|
66
|
+
plugins = (
|
|
67
|
+
eps.select(group="mtcli.plugins")
|
|
68
|
+
if hasattr(eps, "select")
|
|
69
|
+
else eps.get("mtcli.plugins", [])
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
for ep in plugins:
|
|
73
|
+
|
|
74
|
+
plugin = ep.load()
|
|
75
|
+
|
|
76
|
+
if callable(plugin) and not isinstance(plugin, click.Command):
|
|
77
|
+
plugin(cli)
|
|
78
|
+
|
|
79
|
+
elif isinstance(plugin, click.Command):
|
|
80
|
+
cli.add_command(plugin)
|
|
81
|
+
|
|
82
|
+
else:
|
|
83
|
+
raise TypeError(
|
|
84
|
+
f"Plugin {ep.name} inválido: deve ser um comando Click ou função register."
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def load_plugins(cli: click.Group) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Carrega todos os plugins (internos e externos).
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
cli: grupo principal do Click.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
load_internal_plugins(cli)
|
|
97
|
+
load_external_plugins(cli)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Plugin interno de exemplo.
|
|
3
|
+
|
|
4
|
+
Este módulo demonstra como criar um plugin interno
|
|
5
|
+
para o mtcli utilizando a função `register`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.command()
|
|
12
|
+
def exemplo():
|
|
13
|
+
"""
|
|
14
|
+
Comando simples de demonstração.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
click.echo("")
|
|
18
|
+
click.echo("Plugin interno funcionando.")
|
|
19
|
+
click.echo("Este é apenas um exemplo.")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _register(cli):
|
|
23
|
+
"""
|
|
24
|
+
Registra o comando no CLI principal.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
cli: grupo principal do Click.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
cli.add_command(exemplo)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from .cli import mm
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def register(cli):
|
|
5
|
-
cli.add_command(mm, name="mm")
|
|
1
|
+
from .cli import mm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def register(cli):
|
|
5
|
+
cli.add_command(mm, name="mm")
|
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
"""Comando da médiamóvel."""
|
|
2
|
-
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
|
|
5
|
-
import click
|
|
6
|
-
|
|
7
|
-
from mtcli.logger import setup_logger
|
|
8
|
-
from mtcli.models.rates_model import RatesModel
|
|
9
|
-
|
|
10
|
-
from . import conf
|
|
11
|
-
from .models.model_media_movel import MediaMovelModel
|
|
12
|
-
|
|
13
|
-
logger = setup_logger()
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@click.command(
|
|
17
|
-
"mm", help="Calcula a média móvel (SMA ou EMA) para o ativo e período especificado."
|
|
18
|
-
)
|
|
19
|
-
@click.argument("symbol")
|
|
20
|
-
@click.option(
|
|
21
|
-
"--period",
|
|
22
|
-
"-p",
|
|
23
|
-
default="D1",
|
|
24
|
-
help="Tempo gráfico, default D1.",
|
|
25
|
-
)
|
|
26
|
-
@click.option(
|
|
27
|
-
"--periodos",
|
|
28
|
-
"-pe",
|
|
29
|
-
default=conf.periodos,
|
|
30
|
-
help="Quantidade de períodos da média, default 14.",
|
|
31
|
-
)
|
|
32
|
-
@click.option(
|
|
33
|
-
"--tipo",
|
|
34
|
-
default="sma",
|
|
35
|
-
type=click.Choice(["sma", "ema"]),
|
|
36
|
-
help="Tipo de média sma ou ema; default sma.",
|
|
37
|
-
)
|
|
38
|
-
@click.option(
|
|
39
|
-
"--limit",
|
|
40
|
-
type=int,
|
|
41
|
-
default=conf.limite_linhas,
|
|
42
|
-
help="Limita a quantidade de linhas exibidas; default: 5.",
|
|
43
|
-
)
|
|
44
|
-
@click.option(
|
|
45
|
-
"--inicio",
|
|
46
|
-
type=str,
|
|
47
|
-
help="Data/hora inicial no formato YYYY-MM-DD ou YYYY-MM-DD HH:MM.",
|
|
48
|
-
)
|
|
49
|
-
@click.option(
|
|
50
|
-
"--fim", type=str, help="Data/hora final no formato YYYY-MM-DD ou YYYY-MM-DD HH:MM."
|
|
51
|
-
)
|
|
52
|
-
def mm(symbol, period, periodos, tipo, limit, inicio, fim):
|
|
53
|
-
"""
|
|
54
|
-
Calcula a média móvel (SMA ou EMA) do ativo SYMBOL.
|
|
55
|
-
"""
|
|
56
|
-
logger.info(
|
|
57
|
-
f"Iniciando cálculo da média móvel: ativo {symbol} período {period} períodos {periodos} tipo {tipo} limite {limit}"
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
rates = RatesModel(symbol, period).get_data()
|
|
61
|
-
closes = [r[4] for r in rates]
|
|
62
|
-
datas = [r[0] for r in rates]
|
|
63
|
-
|
|
64
|
-
if len(closes) < periodos:
|
|
65
|
-
logger.warning("Dados insuficientes para calcular a média.")
|
|
66
|
-
click.echo("Dados insuficientes para calcular a média.")
|
|
67
|
-
return
|
|
68
|
-
|
|
69
|
-
model_mm = MediaMovelModel(closes, periodos)
|
|
70
|
-
if tipo == "sma":
|
|
71
|
-
media = model_mm.calcula_sma()
|
|
72
|
-
else:
|
|
73
|
-
media = model_mm.calcula_ema()
|
|
74
|
-
|
|
75
|
-
datas = datas[periodos - 1 :]
|
|
76
|
-
|
|
77
|
-
# Filtro por data/hora
|
|
78
|
-
dt_inicio = datetime.fromisoformat(inicio) if inicio else None
|
|
79
|
-
dt_fim = datetime.fromisoformat(fim) if fim else None
|
|
80
|
-
|
|
81
|
-
# formato compatível com '2023.08.31 00:00:00'
|
|
82
|
-
formato = "%Y.%m.%d %H:%M:%S"
|
|
83
|
-
|
|
84
|
-
filtrado = []
|
|
85
|
-
for d, m in zip(datas, media):
|
|
86
|
-
dt = datetime.strptime(d, formato)
|
|
87
|
-
if (not dt_inicio or dt >= dt_inicio) and (not dt_fim or dt <= dt_fim):
|
|
88
|
-
filtrado.append((d, m))
|
|
89
|
-
|
|
90
|
-
if not filtrado:
|
|
91
|
-
click.echo("Nenhum dado no intervalo especificado.")
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
if limit > 0:
|
|
95
|
-
filtrado = filtrado[-limit:]
|
|
96
|
-
|
|
97
|
-
for dt, valor in filtrado:
|
|
98
|
-
click.echo(f"{round(valor, conf.DIGITOS)} {dt}")
|
|
1
|
+
"""Comando da médiamóvel."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from mtcli.logger import setup_logger
|
|
8
|
+
from mtcli.models.rates_model import RatesModel
|
|
9
|
+
|
|
10
|
+
from . import conf
|
|
11
|
+
from .models.model_media_movel import MediaMovelModel
|
|
12
|
+
|
|
13
|
+
logger = setup_logger()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.command(
|
|
17
|
+
"mm", help="Calcula a média móvel (SMA ou EMA) para o ativo e período especificado."
|
|
18
|
+
)
|
|
19
|
+
@click.argument("symbol")
|
|
20
|
+
@click.option(
|
|
21
|
+
"--period",
|
|
22
|
+
"-p",
|
|
23
|
+
default="D1",
|
|
24
|
+
help="Tempo gráfico, default D1.",
|
|
25
|
+
)
|
|
26
|
+
@click.option(
|
|
27
|
+
"--periodos",
|
|
28
|
+
"-pe",
|
|
29
|
+
default=conf.periodos,
|
|
30
|
+
help="Quantidade de períodos da média, default 14.",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
"--tipo",
|
|
34
|
+
default="sma",
|
|
35
|
+
type=click.Choice(["sma", "ema"]),
|
|
36
|
+
help="Tipo de média sma ou ema; default sma.",
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--limit",
|
|
40
|
+
type=int,
|
|
41
|
+
default=conf.limite_linhas,
|
|
42
|
+
help="Limita a quantidade de linhas exibidas; default: 5.",
|
|
43
|
+
)
|
|
44
|
+
@click.option(
|
|
45
|
+
"--inicio",
|
|
46
|
+
type=str,
|
|
47
|
+
help="Data/hora inicial no formato YYYY-MM-DD ou YYYY-MM-DD HH:MM.",
|
|
48
|
+
)
|
|
49
|
+
@click.option(
|
|
50
|
+
"--fim", type=str, help="Data/hora final no formato YYYY-MM-DD ou YYYY-MM-DD HH:MM."
|
|
51
|
+
)
|
|
52
|
+
def mm(symbol, period, periodos, tipo, limit, inicio, fim):
|
|
53
|
+
"""
|
|
54
|
+
Calcula a média móvel (SMA ou EMA) do ativo SYMBOL.
|
|
55
|
+
"""
|
|
56
|
+
logger.info(
|
|
57
|
+
f"Iniciando cálculo da média móvel: ativo {symbol} período {period} períodos {periodos} tipo {tipo} limite {limit}"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
rates = RatesModel(symbol, period).get_data()
|
|
61
|
+
closes = [r[4] for r in rates]
|
|
62
|
+
datas = [r[0] for r in rates]
|
|
63
|
+
|
|
64
|
+
if len(closes) < periodos:
|
|
65
|
+
logger.warning("Dados insuficientes para calcular a média.")
|
|
66
|
+
click.echo("Dados insuficientes para calcular a média.")
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
model_mm = MediaMovelModel(closes, periodos)
|
|
70
|
+
if tipo == "sma":
|
|
71
|
+
media = model_mm.calcula_sma()
|
|
72
|
+
else:
|
|
73
|
+
media = model_mm.calcula_ema()
|
|
74
|
+
|
|
75
|
+
datas = datas[periodos - 1 :]
|
|
76
|
+
|
|
77
|
+
# Filtro por data/hora
|
|
78
|
+
dt_inicio = datetime.fromisoformat(inicio) if inicio else None
|
|
79
|
+
dt_fim = datetime.fromisoformat(fim) if fim else None
|
|
80
|
+
|
|
81
|
+
# formato compatível com '2023.08.31 00:00:00'
|
|
82
|
+
formato = "%Y.%m.%d %H:%M:%S"
|
|
83
|
+
|
|
84
|
+
filtrado = []
|
|
85
|
+
for d, m in zip(datas, media):
|
|
86
|
+
dt = datetime.strptime(d, formato)
|
|
87
|
+
if (not dt_inicio or dt >= dt_inicio) and (not dt_fim or dt <= dt_fim):
|
|
88
|
+
filtrado.append((d, m))
|
|
89
|
+
|
|
90
|
+
if not filtrado:
|
|
91
|
+
click.echo("Nenhum dado no intervalo especificado.")
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
if limit > 0:
|
|
95
|
+
filtrado = filtrado[-limit:]
|
|
96
|
+
|
|
97
|
+
for dt, valor in filtrado:
|
|
98
|
+
click.echo(f"{round(valor, conf.DIGITOS)} {dt}")
|
mtcli-3.6.0.dev0/mtcli/cli.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
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()
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Módulo responsável pelo carregamento de plugins do mtcli.
|
|
3
|
-
|
|
4
|
-
Carrega plugins internos (via mtcli.plugin.register) e plugins externos
|
|
5
|
-
registrados via entry points (`mtcli.plugins`).
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import click
|
|
9
|
-
|
|
10
|
-
try:
|
|
11
|
-
from importlib.metadata import entry_points
|
|
12
|
-
except ImportError:
|
|
13
|
-
from importlib_metadata import entry_points # Para Python < 3.8
|
|
14
|
-
|
|
15
|
-
from mtcli import plugin as internal_plugin
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def load_plugins(cli: click.Group):
|
|
19
|
-
"""
|
|
20
|
-
Carrega todos os plugins (internos e externos) e registra-os no CLI.
|
|
21
|
-
|
|
22
|
-
Args:
|
|
23
|
-
cli (click.Group): grupo Click principal (ex.: `mt`).
|
|
24
|
-
|
|
25
|
-
Comportamento:
|
|
26
|
-
- Plugins internos são registrados via `mtcli.plugin.register(cli)`.
|
|
27
|
-
- Plugins externos são carregados via entry points `mtcli.plugins`.
|
|
28
|
-
- Se o entry point for uma função, chama `plugin(cli)`.
|
|
29
|
-
- Se for um `click.Command`, adiciona diretamente com `cli.add_command()`.
|
|
30
|
-
- Caso contrário, lança TypeError.
|
|
31
|
-
"""
|
|
32
|
-
# --- Carrega plugins internos ---
|
|
33
|
-
internal_plugin.register(cli)
|
|
34
|
-
|
|
35
|
-
# --- Carrega plugins externos via entry points ---
|
|
36
|
-
eps = entry_points()
|
|
37
|
-
plugins = (
|
|
38
|
-
eps.select(group="mtcli.plugins")
|
|
39
|
-
if hasattr(eps, "select")
|
|
40
|
-
else eps.get("mtcli.plugins", [])
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
for ep in plugins:
|
|
44
|
-
try:
|
|
45
|
-
plugin_obj = ep.load()
|
|
46
|
-
except Exception as e:
|
|
47
|
-
raise RuntimeError(f"Falha ao carregar plugin {ep.name}: {e}") from e
|
|
48
|
-
|
|
49
|
-
if callable(plugin_obj) and not isinstance(plugin_obj, click.Command):
|
|
50
|
-
# função register(cli)
|
|
51
|
-
plugin_obj(cli)
|
|
52
|
-
elif isinstance(plugin_obj, click.Command):
|
|
53
|
-
cli.add_command(plugin_obj)
|
|
54
|
-
else:
|
|
55
|
-
raise TypeError(
|
|
56
|
-
f"Plugin {ep.name} inválido: não é um comando nem função register."
|
|
57
|
-
)
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Plugin interno de exemplo para mtcli.
|
|
3
|
-
|
|
4
|
-
Este plugin demonstra como criar um comando interno simples.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import click
|
|
8
|
-
|
|
9
|
-
def register(cli):
|
|
10
|
-
"""
|
|
11
|
-
Registra o comando `hello` no CLI principal.
|
|
12
|
-
|
|
13
|
-
Args:
|
|
14
|
-
cli (click.Group): grupo principal do Click (`mt`)
|
|
15
|
-
"""
|
|
16
|
-
@cli.command()
|
|
17
|
-
@click.option("--name", "-n", default="Mundo", help="Nome para saudação")
|
|
18
|
-
def hello(name):
|
|
19
|
-
"""Exibe uma saudação simples."""
|
|
20
|
-
click.echo(f"Olá, {name}! Este é um plugin interno de exemplo.")
|
|
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.6.0.dev0 → mtcli-3.6.0.dev1}/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.6.0.dev0 → mtcli-3.6.0.dev1}/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.6.0.dev0 → mtcli-3.6.0.dev1}/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
|