mtcli-risco 2.3.0.dev1__tar.gz → 2.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtcli-risco
3
- Version: 2.3.0.dev1
3
+ Version: 2.3.0.dev2
4
4
  Summary: Plugin mtcli para controle de loss diário
5
5
  License-Expression: GPL-3.0
6
6
  License-File: LICENSE
@@ -1,10 +1,11 @@
1
1
  """
2
2
  Modo PANIC CLOSE.
3
3
 
4
- - Funciona em conta hedge e netting
5
- - Detecta market fechado
6
- - Reexecuta automaticamente quando o market abrir
7
- - Suporta modo DRY-RUN (simulação)
4
+ Responsável por:
5
+ - Encerrar TODAS as posições abertas (hedge ou netting)
6
+ - Cancelar TODAS as ordens pendentes
7
+ - Funcionar com market aberto ou fechado (retry automático)
8
+ - Suportar modo DRY-RUN (simulação)
8
9
  """
9
10
 
10
11
  import time
@@ -16,16 +17,25 @@ log = setup_logger()
16
17
 
17
18
 
18
19
  def _trade_permitido() -> bool:
20
+ """
21
+ Verifica se a conta permite trading.
22
+ """
19
23
  info = mt5.account_info()
20
24
  return bool(info and info.trade_allowed)
21
25
 
22
26
 
23
27
  def _market_aberto(symbol: str) -> bool:
28
+ """
29
+ Verifica se o mercado do símbolo está aberto para trading.
30
+ """
24
31
  info = mt5.symbol_info(symbol)
25
32
  return bool(info and info.trade_mode == mt5.SYMBOL_TRADE_MODE_FULL)
26
33
 
27
34
 
28
35
  def _close_position(position, dry_run: bool = False) -> bool:
36
+ """
37
+ Fecha uma posição individual (compatível com hedge e netting).
38
+ """
29
39
  symbol = position.symbol
30
40
  tick = mt5.symbol_info_tick(symbol)
31
41
 
@@ -33,19 +43,19 @@ def _close_position(position, dry_run: bool = False) -> bool:
33
43
  log.error(f"[PANIC] Tick indisponível para {symbol}")
34
44
  return False
35
45
 
36
- tipo = (
46
+ order_type = (
37
47
  mt5.ORDER_TYPE_SELL
38
48
  if position.type == mt5.ORDER_TYPE_BUY
39
49
  else mt5.ORDER_TYPE_BUY
40
50
  )
41
51
 
42
- price = tick.bid if tipo == mt5.ORDER_TYPE_SELL else tick.ask
52
+ price = tick.bid if order_type == mt5.ORDER_TYPE_SELL else tick.ask
43
53
 
44
54
  request = {
45
55
  "action": mt5.TRADE_ACTION_DEAL,
46
56
  "symbol": symbol,
47
57
  "volume": position.volume,
48
- "type": tipo,
58
+ "type": order_type,
49
59
  "price": price,
50
60
  "deviation": 20,
51
61
  "magic": 999999,
@@ -54,6 +64,7 @@ def _close_position(position, dry_run: bool = False) -> bool:
54
64
  "type_filling": mt5.ORDER_FILLING_IOC,
55
65
  }
56
66
 
67
+ # Conta hedge → precisa do ticket
57
68
  if position.ticket:
58
69
  request["position"] = position.ticket
59
70
 
@@ -65,13 +76,15 @@ def _close_position(position, dry_run: bool = False) -> bool:
65
76
 
66
77
  if not result:
67
78
  log.error(
68
- f"[PANIC] order_send None | {symbol} | last_error={mt5.last_error()}"
79
+ f"[PANIC] order_send retornou None | "
80
+ f"{symbol} | last_error={mt5.last_error()}"
69
81
  )
70
82
  return False
71
83
 
72
84
  if result.retcode != mt5.TRADE_RETCODE_DONE:
73
85
  log.error(
74
- f"[PANIC] Falha ao fechar {symbol} | retcode={result.retcode}"
86
+ f"[PANIC] Falha ao fechar posição {symbol} | "
87
+ f"retcode={result.retcode}"
75
88
  )
76
89
  return False
77
90
 
@@ -87,13 +100,21 @@ def panic_close_all(
87
100
  dry_run: bool = False,
88
101
  ) -> dict:
89
102
  """
90
- Executa o fechamento emergencial de posições e ordens.
91
-
92
- retry_on_market_open:
93
- Reexecuta automaticamente quando o market abrir.
94
-
95
- dry_run:
96
- Simula ações sem enviar ordens.
103
+ Executa o fechamento emergencial de TODAS as posições e ordens.
104
+
105
+ Parâmetros
106
+ ----------
107
+ retry_on_market_open : bool
108
+ Reexecuta automaticamente quando o market estiver fechado.
109
+ retry_interval : int
110
+ Intervalo (segundos) entre tentativas quando market fechado.
111
+ dry_run : bool
112
+ Simula as ações sem enviar ordens reais.
113
+
114
+ Retorna
115
+ -------
116
+ dict
117
+ Estatísticas da execução do panic close.
97
118
  """
98
119
  stats = {
99
120
  "positions_total": 0,
@@ -105,6 +126,8 @@ def panic_close_all(
105
126
  }
106
127
 
107
128
  while True:
129
+ market_fechado = False
130
+
108
131
  with mt5_conexao():
109
132
  if not _trade_permitido():
110
133
  log.critical("[PANIC] Trading desabilitado na conta!")
@@ -117,9 +140,7 @@ def panic_close_all(
117
140
  if positions:
118
141
  stats["positions_total"] = len(positions)
119
142
 
120
- market_fechado = False
121
-
122
- # 1️⃣ Fechar posições
143
+ # 1️⃣ Fechamento de posições
123
144
  if positions:
124
145
  for pos in positions:
125
146
  if not _market_aberto(pos.symbol):
@@ -132,25 +153,40 @@ def panic_close_all(
132
153
  if _close_position(pos, dry_run=dry_run):
133
154
  stats["positions_closed"] += 1
134
155
 
135
- # 2️⃣ Cancelar ordens pendentes
156
+ # 2️⃣ Cancelamento de ordens pendentes
136
157
  if orders:
137
158
  for ordem in orders:
138
159
  if dry_run:
139
160
  log.warning(
140
- f"[PANIC][DRY] Cancelamento simulado | ticket={ordem.ticket}"
161
+ f"[PANIC][DRY] Cancelamento simulado | "
162
+ f"ticket={ordem.ticket}"
141
163
  )
142
164
  stats["orders_cancelled"] += 1
143
165
  continue
144
166
 
145
- result = mt5.order_delete(ordem.ticket)
146
- if result and result.retcode == mt5.TRADE_RETCODE_DONE:
167
+ request = {
168
+ "action": mt5.TRADE_ACTION_REMOVE,
169
+ "order": ordem.ticket,
170
+ }
171
+
172
+ result = mt5.order_send(request)
173
+
174
+ if not result:
175
+ log.error(
176
+ f"[PANIC] Falha ao cancelar ordem {ordem.ticket} | "
177
+ f"last_error={mt5.last_error()}"
178
+ )
179
+ continue
180
+
181
+ if result.retcode == mt5.TRADE_RETCODE_DONE:
147
182
  stats["orders_cancelled"] += 1
148
183
  log.warning(
149
184
  f"[PANIC] Ordem cancelada | ticket={ordem.ticket}"
150
185
  )
151
186
  else:
152
187
  log.error(
153
- f"[PANIC] Falha ao cancelar ordem {ordem.ticket}"
188
+ f"[PANIC] Falha ao cancelar ordem {ordem.ticket} | "
189
+ f"retcode={result.retcode}"
154
190
  )
155
191
 
156
192
  if not market_fechado:
@@ -162,7 +198,7 @@ def panic_close_all(
162
198
  break
163
199
 
164
200
  log.critical(
165
- f"[PANIC] Market fechado. Repetindo em {retry_interval}s..."
201
+ f"[PANIC] Market fechado. Nova tentativa em {retry_interval}s..."
166
202
  )
167
203
  time.sleep(retry_interval)
168
204
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mtcli-risco"
3
- version = "2.3.0.dev1"
3
+ version = "2.3.0.dev2"
4
4
  description = "Plugin mtcli para controle de loss diário"
5
5
  authors = [
6
6
  {name = "Valmir França da Silva",email = "vfranca3@gmail.com"}