mtcli-renko 1.1.0.dev0__tar.gz → 1.1.0.dev2__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_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/PKG-INFO +1 -1
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/commands/renko.py +12 -4
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/conf.py +5 -0
- mtcli_renko-1.1.0.dev2/mtcli_renko/controllers/renko_controller.py +105 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/models/renko_model.py +58 -99
- mtcli_renko-1.1.0.dev2/mtcli_renko/views/renko_view.py +75 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/pyproject.toml +1 -1
- mtcli_renko-1.1.0.dev0/mtcli_renko/controllers/renko_controller.py +0 -66
- mtcli_renko-1.1.0.dev0/mtcli_renko/views/renko_view.py +0 -37
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/LICENSE +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/README.md +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/__init__.py +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/commands/__init__.py +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/controllers/__init__.py +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/domain/__init__.py +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/domain/timeframe.py +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/models/__init__.py +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/plugin.py +0 -0
- {mtcli_renko-1.1.0.dev0 → mtcli_renko-1.1.0.dev2}/mtcli_renko/views/__init__.py +0 -0
|
@@ -8,7 +8,7 @@ from ..controllers.renko_controller import RenkoController
|
|
|
8
8
|
from ..views.renko_view import exibir_renko
|
|
9
9
|
from ..domain.timeframe import Timeframe
|
|
10
10
|
from mtcli.logger import setup_logger
|
|
11
|
-
from ..conf import SYMBOL, BRICK, PERIOD, BARS, DATA_MODE, MAX_TICKS
|
|
11
|
+
from ..conf import SYMBOL, BRICK, PERIOD, BARS, DATA_MODE, MAX_TICKS, TICK_STYLE
|
|
12
12
|
|
|
13
13
|
log = setup_logger(__name__)
|
|
14
14
|
|
|
@@ -43,7 +43,13 @@ log = setup_logger(__name__)
|
|
|
43
43
|
default=MAX_TICKS,
|
|
44
44
|
show_default=True,
|
|
45
45
|
type=int,
|
|
46
|
-
|
|
46
|
+
)
|
|
47
|
+
@click.option(
|
|
48
|
+
"--tick-style",
|
|
49
|
+
type=click.Choice(["estrutural", "hibrido", "agressivo"], case_sensitive=False),
|
|
50
|
+
default=TICK_STYLE,
|
|
51
|
+
show_default=True,
|
|
52
|
+
help="Define como tratar brick em formação no modo tick.",
|
|
47
53
|
)
|
|
48
54
|
def renko(
|
|
49
55
|
symbol,
|
|
@@ -55,6 +61,7 @@ def renko(
|
|
|
55
61
|
ancorar_abertura,
|
|
56
62
|
data_mode,
|
|
57
63
|
max_ticks,
|
|
64
|
+
tick_style,
|
|
58
65
|
):
|
|
59
66
|
|
|
60
67
|
try:
|
|
@@ -71,7 +78,8 @@ def renko(
|
|
|
71
78
|
ancorar_abertura,
|
|
72
79
|
data_mode,
|
|
73
80
|
max_ticks,
|
|
81
|
+
tick_style,
|
|
74
82
|
)
|
|
75
83
|
|
|
76
|
-
|
|
77
|
-
exibir_renko(
|
|
84
|
+
resultado = controller.executar()
|
|
85
|
+
exibir_renko(resultado, numerar=numerar)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Renko controller.
|
|
3
|
+
|
|
4
|
+
Responsável por:
|
|
5
|
+
- Orquestrar obtenção de dados (candle ou tick)
|
|
6
|
+
- Chamar o model
|
|
7
|
+
- Aplicar estilo de saída no modo tick
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from ..models.renko_model import RenkoModel
|
|
11
|
+
from mtcli.logger import setup_logger
|
|
12
|
+
|
|
13
|
+
log = setup_logger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RenkoController:
|
|
17
|
+
"""
|
|
18
|
+
Controller principal do Renko.
|
|
19
|
+
|
|
20
|
+
:param symbol: ativo (ex: WINJ26)
|
|
21
|
+
:param brick_size: tamanho do brick
|
|
22
|
+
:param timeframe: timeframe MT5 (para candle)
|
|
23
|
+
:param quantidade: número de candles
|
|
24
|
+
:param modo: simples ou classico
|
|
25
|
+
:param ancorar_abertura: ancora na abertura da sessão
|
|
26
|
+
:param data_mode: candle ou tick
|
|
27
|
+
:param max_ticks: quantidade máxima de ticks
|
|
28
|
+
:param tick_style: estrutural | hibrido | agressivo
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
symbol,
|
|
34
|
+
brick_size,
|
|
35
|
+
timeframe,
|
|
36
|
+
quantidade,
|
|
37
|
+
modo="simples",
|
|
38
|
+
ancorar_abertura=False,
|
|
39
|
+
data_mode="candle",
|
|
40
|
+
max_ticks=3000,
|
|
41
|
+
tick_style="hibrido",
|
|
42
|
+
):
|
|
43
|
+
self.model = RenkoModel(symbol, brick_size)
|
|
44
|
+
self.timeframe = timeframe
|
|
45
|
+
self.quantidade = quantidade
|
|
46
|
+
self.modo = modo
|
|
47
|
+
self.ancorar_abertura = ancorar_abertura
|
|
48
|
+
self.data_mode = data_mode
|
|
49
|
+
self.max_ticks = max_ticks
|
|
50
|
+
self.tick_style = tick_style
|
|
51
|
+
|
|
52
|
+
def executar(self):
|
|
53
|
+
"""
|
|
54
|
+
Executa construção do Renko conforme modo configurado.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
# =========================
|
|
58
|
+
# MODO TICK
|
|
59
|
+
# =========================
|
|
60
|
+
if self.data_mode == "tick":
|
|
61
|
+
|
|
62
|
+
ticks = self.model.obter_ticks(
|
|
63
|
+
timeframe=self.timeframe,
|
|
64
|
+
max_ticks=self.max_ticks,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# 🔒 Correção definitiva do erro numpy
|
|
68
|
+
if ticks is None or len(ticks) == 0:
|
|
69
|
+
return []
|
|
70
|
+
|
|
71
|
+
resultado = self.model.construir_renko_ticks(ticks)
|
|
72
|
+
|
|
73
|
+
# =========================
|
|
74
|
+
# Aplicar estilo de tick
|
|
75
|
+
# =========================
|
|
76
|
+
|
|
77
|
+
# Estrutural → somente confirmados
|
|
78
|
+
if self.tick_style == "estrutural":
|
|
79
|
+
return resultado.confirmados
|
|
80
|
+
|
|
81
|
+
# Agressivo → confirmados + parcial como válido
|
|
82
|
+
if self.tick_style == "agressivo":
|
|
83
|
+
if resultado.em_formacao:
|
|
84
|
+
return resultado.confirmados + [resultado.em_formacao]
|
|
85
|
+
return resultado.confirmados
|
|
86
|
+
|
|
87
|
+
# Híbrido (default) → retorna objeto completo
|
|
88
|
+
return resultado
|
|
89
|
+
|
|
90
|
+
# =========================
|
|
91
|
+
# MODO CANDLE
|
|
92
|
+
# =========================
|
|
93
|
+
rates = self.model.obter_rates(
|
|
94
|
+
self.timeframe,
|
|
95
|
+
self.quantidade,
|
|
96
|
+
ancorar_abertura=self.ancorar_abertura,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if rates is None or len(rates) == 0:
|
|
100
|
+
return []
|
|
101
|
+
|
|
102
|
+
return self.model.construir_renko(
|
|
103
|
+
rates,
|
|
104
|
+
modo=self.modo,
|
|
105
|
+
)
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Renko model institucional profissional.
|
|
3
3
|
|
|
4
|
-
✔
|
|
5
|
-
✔
|
|
4
|
+
✔ Candle mode determinístico
|
|
5
|
+
✔ Tick mode híbrido (confirmados + em formação)
|
|
6
|
+
✔ Estrutura estável
|
|
6
7
|
✔ Compatível com controller atual
|
|
7
|
-
✔ Seguro para numpy arrays
|
|
8
|
-
✔ Funciona fora do pregão
|
|
9
8
|
"""
|
|
10
9
|
|
|
11
10
|
from dataclasses import dataclass
|
|
12
|
-
from typing import List, Optional
|
|
13
|
-
from datetime import datetime
|
|
11
|
+
from typing import List, Optional, NamedTuple
|
|
12
|
+
from datetime import datetime
|
|
14
13
|
|
|
15
14
|
import MetaTrader5 as mt5
|
|
16
15
|
|
|
@@ -22,7 +21,7 @@ log = setup_logger(__name__)
|
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
# ==========================================================
|
|
25
|
-
# DATA
|
|
24
|
+
# DATA STRUCTURES
|
|
26
25
|
# ==========================================================
|
|
27
26
|
|
|
28
27
|
@dataclass
|
|
@@ -32,6 +31,11 @@ class RenkoBrick:
|
|
|
32
31
|
close: float
|
|
33
32
|
|
|
34
33
|
|
|
34
|
+
class RenkoResult(NamedTuple):
|
|
35
|
+
confirmados: List[RenkoBrick]
|
|
36
|
+
em_formacao: Optional[RenkoBrick]
|
|
37
|
+
|
|
38
|
+
|
|
35
39
|
# ==========================================================
|
|
36
40
|
# MODEL
|
|
37
41
|
# ==========================================================
|
|
@@ -43,7 +47,7 @@ class RenkoModel:
|
|
|
43
47
|
self.brick_size = brick_size
|
|
44
48
|
|
|
45
49
|
# ======================================================
|
|
46
|
-
# AUXILIAR
|
|
50
|
+
# AUXILIAR
|
|
47
51
|
# ======================================================
|
|
48
52
|
|
|
49
53
|
def _ultimo_pregao_data(self, timeframe):
|
|
@@ -72,10 +76,6 @@ class RenkoModel:
|
|
|
72
76
|
if not mt5.symbol_select(self.symbol, True):
|
|
73
77
|
raise RuntimeError(f"Erro ao selecionar símbolo {self.symbol}")
|
|
74
78
|
|
|
75
|
-
# -------------------------------------------------
|
|
76
|
-
# SEM ANCORAGEM
|
|
77
|
-
# -------------------------------------------------
|
|
78
|
-
|
|
79
79
|
if not ancorar_abertura:
|
|
80
80
|
|
|
81
81
|
if quantidade == 0:
|
|
@@ -88,14 +88,7 @@ class RenkoModel:
|
|
|
88
88
|
quantidade,
|
|
89
89
|
)
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
return []
|
|
93
|
-
|
|
94
|
-
return rates
|
|
95
|
-
|
|
96
|
-
# -------------------------------------------------
|
|
97
|
-
# COM ANCORAGEM REAL POR DATA
|
|
98
|
-
# -------------------------------------------------
|
|
91
|
+
return rates or []
|
|
99
92
|
|
|
100
93
|
data_pregao = self._ultimo_pregao_data(timeframe)
|
|
101
94
|
|
|
@@ -119,21 +112,13 @@ class RenkoModel:
|
|
|
119
112
|
if r_time.date() == data_pregao:
|
|
120
113
|
filtrado.append(r)
|
|
121
114
|
|
|
122
|
-
if not filtrado:
|
|
123
|
-
return []
|
|
124
|
-
|
|
125
|
-
total = len(filtrado)
|
|
126
|
-
|
|
127
115
|
if quantidade == 0:
|
|
128
116
|
return filtrado
|
|
129
117
|
|
|
130
|
-
if quantidade >= total:
|
|
131
|
-
return filtrado
|
|
132
|
-
|
|
133
118
|
return filtrado[-quantidade:]
|
|
134
119
|
|
|
135
120
|
# ======================================================
|
|
136
|
-
# TICKS
|
|
121
|
+
# TICKS
|
|
137
122
|
# ======================================================
|
|
138
123
|
|
|
139
124
|
def obter_ticks(self, timeframe, max_ticks=5000):
|
|
@@ -153,110 +138,62 @@ class RenkoModel:
|
|
|
153
138
|
datetime.strptime(SESSION_OPEN, "%H:%M").time(),
|
|
154
139
|
)
|
|
155
140
|
|
|
156
|
-
|
|
141
|
+
agora = datetime.now()
|
|
142
|
+
|
|
143
|
+
ticks = mt5.copy_ticks_range(
|
|
157
144
|
self.symbol,
|
|
158
145
|
inicio,
|
|
159
|
-
|
|
146
|
+
agora,
|
|
160
147
|
mt5.COPY_TICKS_ALL,
|
|
161
148
|
)
|
|
162
149
|
|
|
163
|
-
if ticks is None:
|
|
150
|
+
if ticks is None or len(ticks) == 0:
|
|
164
151
|
return []
|
|
165
152
|
|
|
153
|
+
if len(ticks) > max_ticks:
|
|
154
|
+
ticks = ticks[-max_ticks:]
|
|
155
|
+
|
|
166
156
|
return ticks
|
|
167
157
|
|
|
168
158
|
# ======================================================
|
|
169
159
|
# CONSTRUÇÃO RENKO (CANDLE)
|
|
170
160
|
# ======================================================
|
|
171
161
|
|
|
172
|
-
def construir_renko(
|
|
173
|
-
self,
|
|
174
|
-
rates,
|
|
175
|
-
modo="simples",
|
|
176
|
-
) -> List[RenkoBrick]:
|
|
162
|
+
def construir_renko(self, rates, modo="simples") -> List[RenkoBrick]:
|
|
177
163
|
|
|
178
164
|
if rates is None or len(rates) < 2:
|
|
179
165
|
return []
|
|
180
166
|
|
|
181
167
|
bricks: List[RenkoBrick] = []
|
|
182
|
-
|
|
183
168
|
last_price = float(rates[0]["open"])
|
|
184
|
-
direction: Optional[str] = None
|
|
185
169
|
|
|
186
170
|
for rate in rates[1:]:
|
|
187
171
|
|
|
188
172
|
high = float(rate["high"])
|
|
189
173
|
low = float(rate["low"])
|
|
190
174
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
last_price = novo
|
|
201
|
-
|
|
202
|
-
while last_price - low >= self.brick_size:
|
|
203
|
-
novo = last_price - self.brick_size
|
|
204
|
-
bricks.append(RenkoBrick("down", last_price, novo))
|
|
205
|
-
last_price = novo
|
|
206
|
-
|
|
207
|
-
# -------------------------------------------------
|
|
208
|
-
# MODO CLÁSSICO (reversão 2x)
|
|
209
|
-
# -------------------------------------------------
|
|
210
|
-
|
|
211
|
-
elif modo == "classico":
|
|
212
|
-
|
|
213
|
-
if direction in (None, "up"):
|
|
214
|
-
|
|
215
|
-
while high - last_price >= self.brick_size:
|
|
216
|
-
novo = last_price + self.brick_size
|
|
217
|
-
bricks.append(RenkoBrick("up", last_price, novo))
|
|
218
|
-
last_price = novo
|
|
219
|
-
direction = "up"
|
|
220
|
-
|
|
221
|
-
if (
|
|
222
|
-
direction == "up"
|
|
223
|
-
and last_price - low >= 2 * self.brick_size
|
|
224
|
-
):
|
|
225
|
-
novo = last_price - self.brick_size
|
|
226
|
-
bricks.append(RenkoBrick("down", last_price, novo))
|
|
227
|
-
last_price = novo
|
|
228
|
-
direction = "down"
|
|
229
|
-
|
|
230
|
-
if direction in (None, "down"):
|
|
231
|
-
|
|
232
|
-
while last_price - low >= self.brick_size:
|
|
233
|
-
novo = last_price - self.brick_size
|
|
234
|
-
bricks.append(RenkoBrick("down", last_price, novo))
|
|
235
|
-
last_price = novo
|
|
236
|
-
direction = "down"
|
|
237
|
-
|
|
238
|
-
if (
|
|
239
|
-
direction == "down"
|
|
240
|
-
and high - last_price >= 2 * self.brick_size
|
|
241
|
-
):
|
|
242
|
-
novo = last_price + self.brick_size
|
|
243
|
-
bricks.append(RenkoBrick("up", last_price, novo))
|
|
244
|
-
last_price = novo
|
|
245
|
-
direction = "up"
|
|
175
|
+
while high - last_price >= self.brick_size:
|
|
176
|
+
novo = last_price + self.brick_size
|
|
177
|
+
bricks.append(RenkoBrick("up", last_price, novo))
|
|
178
|
+
last_price = novo
|
|
179
|
+
|
|
180
|
+
while last_price - low >= self.brick_size:
|
|
181
|
+
novo = last_price - self.brick_size
|
|
182
|
+
bricks.append(RenkoBrick("down", last_price, novo))
|
|
183
|
+
last_price = novo
|
|
246
184
|
|
|
247
185
|
return bricks
|
|
248
186
|
|
|
249
187
|
# ======================================================
|
|
250
|
-
# CONSTRUÇÃO RENKO (TICK)
|
|
188
|
+
# CONSTRUÇÃO RENKO (TICK HÍBRIDO)
|
|
251
189
|
# ======================================================
|
|
252
190
|
|
|
253
|
-
def construir_renko_ticks(self, ticks) ->
|
|
191
|
+
def construir_renko_ticks(self, ticks) -> RenkoResult:
|
|
254
192
|
|
|
255
193
|
if ticks is None or len(ticks) < 2:
|
|
256
|
-
return []
|
|
194
|
+
return RenkoResult([], None)
|
|
257
195
|
|
|
258
196
|
bricks: List[RenkoBrick] = []
|
|
259
|
-
|
|
260
197
|
last_price = float(ticks[0]["last"])
|
|
261
198
|
|
|
262
199
|
for tick in ticks[1:]:
|
|
@@ -273,4 +210,26 @@ class RenkoModel:
|
|
|
273
210
|
bricks.append(RenkoBrick("down", last_price, novo))
|
|
274
211
|
last_price = novo
|
|
275
212
|
|
|
276
|
-
|
|
213
|
+
# ----------------------------
|
|
214
|
+
# Brick em formação
|
|
215
|
+
# ----------------------------
|
|
216
|
+
|
|
217
|
+
ultimo_preco = float(ticks[-1]["last"])
|
|
218
|
+
diferenca = ultimo_preco - last_price
|
|
219
|
+
|
|
220
|
+
em_formacao = None
|
|
221
|
+
|
|
222
|
+
if abs(diferenca) > 0:
|
|
223
|
+
|
|
224
|
+
direcao = "up" if diferenca > 0 else "down"
|
|
225
|
+
|
|
226
|
+
em_formacao = RenkoBrick(
|
|
227
|
+
direction=direcao,
|
|
228
|
+
open=last_price,
|
|
229
|
+
close=ultimo_preco,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
return RenkoResult(
|
|
233
|
+
confirmados=bricks,
|
|
234
|
+
em_formacao=em_formacao,
|
|
235
|
+
)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Renko view acessível.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from ..conf import DIGITS
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def exibir_renko(resultado, numerar: bool = False):
|
|
10
|
+
|
|
11
|
+
if not resultado:
|
|
12
|
+
click.echo("Nenhum bloco Renko gerado.")
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
# Lista simples (estrutural ou agressivo)
|
|
16
|
+
if isinstance(resultado, list):
|
|
17
|
+
|
|
18
|
+
click.echo("=== GRAFICO RENKO ===")
|
|
19
|
+
click.echo(f"Total de blocos: {len(resultado)}")
|
|
20
|
+
click.echo()
|
|
21
|
+
|
|
22
|
+
for i, brick in enumerate(resultado, start=1):
|
|
23
|
+
|
|
24
|
+
if numerar:
|
|
25
|
+
linha = (
|
|
26
|
+
f"{i} "
|
|
27
|
+
f"{brick.direction.upper()} "
|
|
28
|
+
f"{brick.open:.{DIGITS}f} "
|
|
29
|
+
f"{brick.close:.{DIGITS}f}"
|
|
30
|
+
)
|
|
31
|
+
else:
|
|
32
|
+
linha = (
|
|
33
|
+
f"{brick.direction.upper()} "
|
|
34
|
+
f"{brick.open:.{DIGITS}f} "
|
|
35
|
+
f"{brick.close:.{DIGITS}f}"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
click.echo(linha)
|
|
39
|
+
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
# Híbrido
|
|
43
|
+
confirmados = resultado.confirmados
|
|
44
|
+
em_formacao = resultado.em_formacao
|
|
45
|
+
|
|
46
|
+
click.echo("=== GRAFICO RENKO ===")
|
|
47
|
+
click.echo(f"Blocos confirmados: {len(confirmados)}")
|
|
48
|
+
click.echo()
|
|
49
|
+
|
|
50
|
+
for i, brick in enumerate(confirmados, start=1):
|
|
51
|
+
|
|
52
|
+
if numerar:
|
|
53
|
+
linha = (
|
|
54
|
+
f"{i} "
|
|
55
|
+
f"{brick.direction.upper()} "
|
|
56
|
+
f"{brick.open:.{DIGITS}f} "
|
|
57
|
+
f"{brick.close:.{DIGITS}f}"
|
|
58
|
+
)
|
|
59
|
+
else:
|
|
60
|
+
linha = (
|
|
61
|
+
f"{brick.direction.upper()} "
|
|
62
|
+
f"{brick.open:.{DIGITS}f} "
|
|
63
|
+
f"{brick.close:.{DIGITS}f}"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
click.echo(linha)
|
|
67
|
+
|
|
68
|
+
if em_formacao:
|
|
69
|
+
click.echo()
|
|
70
|
+
click.echo("EM FORMACAO:")
|
|
71
|
+
click.echo(
|
|
72
|
+
f"{em_formacao.direction.upper()} "
|
|
73
|
+
f"{em_formacao.open:.{DIGITS}f} "
|
|
74
|
+
f"{em_formacao.close:.{DIGITS}f}"
|
|
75
|
+
)
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Renko controller.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from ..models.renko_model import RenkoModel
|
|
6
|
-
from mtcli.logger import setup_logger
|
|
7
|
-
|
|
8
|
-
log = setup_logger(__name__)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class RenkoController:
|
|
12
|
-
|
|
13
|
-
def __init__(
|
|
14
|
-
self,
|
|
15
|
-
symbol,
|
|
16
|
-
brick_size,
|
|
17
|
-
timeframe,
|
|
18
|
-
quantidade,
|
|
19
|
-
modo="simples",
|
|
20
|
-
ancorar_abertura=False,
|
|
21
|
-
data_mode="candle",
|
|
22
|
-
max_ticks=3000,
|
|
23
|
-
):
|
|
24
|
-
self.model = RenkoModel(symbol, brick_size)
|
|
25
|
-
self.timeframe = timeframe
|
|
26
|
-
self.quantidade = quantidade
|
|
27
|
-
self.modo = modo
|
|
28
|
-
self.ancorar_abertura = ancorar_abertura
|
|
29
|
-
self.data_mode = data_mode
|
|
30
|
-
self.max_ticks = max_ticks
|
|
31
|
-
|
|
32
|
-
def executar(self):
|
|
33
|
-
|
|
34
|
-
# -------------------------------------------------
|
|
35
|
-
# TICK MODE
|
|
36
|
-
# -------------------------------------------------
|
|
37
|
-
|
|
38
|
-
if self.data_mode == "tick":
|
|
39
|
-
|
|
40
|
-
ticks = self.model.obter_ticks(
|
|
41
|
-
timeframe=self.timeframe,
|
|
42
|
-
max_ticks=self.max_ticks,
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
if ticks is None or len(ticks) == 0:
|
|
46
|
-
return []
|
|
47
|
-
|
|
48
|
-
return self.model.construir_renko_ticks(ticks)
|
|
49
|
-
|
|
50
|
-
# -------------------------------------------------
|
|
51
|
-
# CANDLE MODE
|
|
52
|
-
# -------------------------------------------------
|
|
53
|
-
|
|
54
|
-
rates = self.model.obter_rates(
|
|
55
|
-
self.timeframe,
|
|
56
|
-
self.quantidade,
|
|
57
|
-
ancorar_abertura=self.ancorar_abertura,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
if rates is None or len(rates) == 0:
|
|
61
|
-
return []
|
|
62
|
-
|
|
63
|
-
return self.model.construir_renko(
|
|
64
|
-
rates,
|
|
65
|
-
modo=self.modo,
|
|
66
|
-
)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Renko view.
|
|
3
|
-
|
|
4
|
-
Saída textual acessível para leitores de tela.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import click
|
|
8
|
-
from ..conf import DIGITS
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def exibir_renko(bricks, numerar: bool = False):
|
|
12
|
-
|
|
13
|
-
if not bricks:
|
|
14
|
-
click.echo("Nenhum bloco Renko gerado.")
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
click.echo("=== GRAFICO RENKO ===")
|
|
18
|
-
click.echo(f"Total de blocos: {len(bricks)}")
|
|
19
|
-
click.echo()
|
|
20
|
-
|
|
21
|
-
for i, brick in enumerate(bricks, start=1):
|
|
22
|
-
|
|
23
|
-
if numerar:
|
|
24
|
-
linha = (
|
|
25
|
-
f"{i} "
|
|
26
|
-
f"{brick.direction.upper()} "
|
|
27
|
-
f"{brick.open:.{DIGITS}f} "
|
|
28
|
-
f"{brick.close:.{DIGITS}f}"
|
|
29
|
-
)
|
|
30
|
-
else:
|
|
31
|
-
linha = (
|
|
32
|
-
f"{brick.direction.upper()} "
|
|
33
|
-
f"{brick.open:.{DIGITS}f} "
|
|
34
|
-
f"{brick.close:.{DIGITS}f}"
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
click.echo(linha)
|
|
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
|