o
    <(;j                    @   s  d Z ddlZddlZddlZddlZddlmZ ddlZddl	Z	ddl
Z
ddlZddlmZmZ ddlZddlmZmZmZ ddlmZ zddlZW n eyU   dZY nw zddlZdZW n eyn   dZed	 Y nw z
dd
lmZ dZW n ey   dZdd ZY nw e  dd Zdd Zdd Zdd Z dd Z!dd Z"z	e	#e	j$d W n e	j%y   z	e	#e	j$d W n
 e	j%y   Y nw Y nw edZ&e&'ddZ(e&'ddZ)e&'ddZ*e&'d dZ+e&'d!dZ,e&'d"d#Z-e.e&'d$d%Z/e0e&'d&d'Z1e0e&'d(d'Z2e&'d)d*Z3e.e&'d+d,Z4e.e&'d-d.d/ Z5e.e&'d0d1Z6e.e&'d2d/Z7d3Z8e&'d4dZ9e.e&'d5d6Z:e&'d7dZ;e&'d8dZ<e&'d9g Z=d:Z>d;Z?e@ ZAeABejC eAjDdd D ]ZEeAFeE qkee>d<d=d>d?ZGeGBejC eHd@ZIeGJeI eAKeG eLdAZLdBdC ZMeM aNe,re*ZOe+ZPne(ZOe)ZPeQeOePddDdEtNdFdGZRe,reRSd eTdH eUdH n	eTdI eUdI e9reTdJ eUdJ n	eTdK eUdK eTdLe8dMdN eUdLe8dMdN eTdOe7dMdP eUdOe7dMdP zeRV  eTdQ eUejWdR ejX  W n" eYyE ZZ ze[dSeZ  eUdSeZ  W Y dZZ[ZndZZ[Zww dTdU Z\dVdW Z]dXdY Z^dZd[ Z_d\d] Z`d^d_ Zad`da Zbdbdc Zcddde Zddfdg Zedhdi ZfddjdkZgdldm Zhdndo Zidpdq Zjdrds Zkdtdu Zldvdw Zmdxdy Zndzd{ Zod|d} Zpd~d Zqdd Zrdd ZsdddZtdd Zudd Zvdd Zwdd ZxdddZydd Zzdd Z{dd Z|dd Z}dd Z~dd Zdd Zedkre  dS dS )u   
ROBÔ DE BALANCEAMENTO DE PORTFÓLIO
Permite operação simultânea em múltiplas moedas com rebalanceamento automático
Baseado na estrutura do robo_trade.py
    N)RotatingFileHandler)datetime	timedelta)initForeStyle)DecimalTFu=   ⚠ requests não instalado - SQLite não estará disponível)obter_url_apic                   C   s   dS )Nz%http://localhost/projetos/rex/api.php r
   r
   r
   3/var/www/html/robo.fernandesemelo.com.br/rex/rex.pyr	   *   s   r	   c                 C   s<   t | ddd}t|W  d   S 1 sw   Y  dS )u'   Carrega configurações do arquivo JSONrutf-8encodingN)openjsonload)filepathfiler
   r
   r   carregar_configuracoes1   s   $r   c                 C   sF   t | ddd}tj||ddd W d   dS 1 sw   Y  dS )u"   Salva o estado atual do portfóliowr   r      Findentensure_asciiN)r   r   dump)r   estador   r
   r
   r   salvar_estado_portfolio6   s   "r   c           
   
   C   s  t sdS zGt }d| |t|t|t|d}tj||dd}|  | }|dr=t	d|d d	|   W d
S t
d|dd  W dS  tjjy\   t
d Y dS  tjjyl   t
d Y dS  ty }	 zt
dt|	  W Y d}	~	dS d}	~	ww )u  
    Registra um trade no banco de dados SQLite via API HTTP
    
    Args:
        moeda (str): Código da moeda (BTC, ETH, etc)
        tipo (str): Tipo de trade:
            - compra_inicial: Compra na fase inicial de construção do portfólio
            - venda_balanceamento: Venda durante rebalanceamento normal
            - compra_balanceamento: Compra durante rebalanceamento normal
            - compra_ajuste_capital: Compra quando capital é incrementado (novo capital investido)
            - venda_ajuste_capital: Venda quando capital é diminuído (capital retirado)
        preco (float): Preço unitário
        quantidade (float): Quantidade
        valor (float): Valor total
    
    Returns:
        bool: True se registrado com sucesso, False caso contrário
    FZ	registrar)Zmetodomoedatipopreco
quantidadevalor   )r   timeoutZsucessou#   ✓ Trade registrado no SQLite: ID Ztrade_idz - Tu!   ⚠ Erro ao registrar no SQLite: ZerroZDesconhecidou5   ⚠ Timeout ao registrar trade no SQLite (API lenta?)uG   ⚠ Erro de conexão ao registrar trade no SQLite (Apache/PHP rodando?)u'   ⚠ Erro ao registrar trade no SQLite: N)SQLITE_DISPONIVELr	   floatrequestspostZraise_for_statusr   getloggingdebugwarning
exceptionsZTimeoutConnectionError	Exceptionstr)
r   r   r    r!   r"   urlZpayloadZrespostaZ	resultadoer
   r
   r   registrar_trade_sqlite;   s<   



r3   c              
   C   s   z=t j| r;t| ddd%}t|}|r |W  d   W S td|  d 	 W d   W dS 1 s6w   Y  W dS  tjy\ } zt	d|  d|  W Y d}~dS d}~w t
yv } zt	d	|  W Y d}~dS d}~ww )
u)   Carrega o estado do portfólio se existirr   r   r   NzArquivo u    está vaziozErro ao decodificar JSON em : zErro ao carregar estado: )ospathexistsr   r   r   r*   r,   JSONDecodeErrorerrorr/   )r   r   datar2   r
   r
   r   carregar_estado_portfoliou   s(   
"r;   c           	   
   C   sh  zt j| r$t| ddd}t|}W d   n1 sw   Y  ni }d|vr.i |d< |D ]4}||d}|dksB||d v rdt|trQt	|
td}nt	tt|
td}||d |< q0tt |d< t| d	dd}tj||d
dd W d   n1 sw   Y  td|   W dS  ty } ztd|  W Y d}~dS d}~ww )uE  
    ✓ NOVO: Salva as quantidades REAIS de cada moeda no portfolio_estado.json
    Isso serve como "fonte de verdade" para recuperação em caso de parada do robô
    
    Args:
        filepath: Caminho do arquivo de estado
        moedas: Lista de moedas
        saldos: Dicionário com os saldos atuais da exchange
    r   r   r   Nquantidade_carteira_realr   
0.00000001Ztimestamp_carteira_realr   r   Fr   u,   ✓ Quantidades reais da carteira salvas em z%Erro ao atualizar quantidades reais: )r5   r6   r7   r   r   r   r)   
isinstancer   r&   quantizer0   r   nowtimezone	isoformatr   r*   infor/   r9   )	r   moedassaldosr   r   r   saldoZsaldo_precisor2   r
   r
   r   "atualizar_quantidade_carteira_real   s4   

rG   c                 C   s  i }d| vr|S | d }d}|D ]_}||v ro|| }| |d}tt|}	tt|}
tt|
|	 }||krot|tt|	t|
| d }|dkrot|	tdt|
tdt|
|	 tdt|dd||< q|rt	d	 t	d
 |
 D ]7\}}t	d| d t	d|d  d|  t	d|d  d|  t	d|d  d|d  d qt	d t	d |S )u  
    ✓ NOVO: Verifica se há discrepâncias entre as quantidades salvas e as atuais
    Se houver diferenças significativas, registra em log para auditoría
    
    Args:
        estado: Estado do portfólio carregado
        moedas: Lista de moedas
        saldos: Dicionário com saldos atuais da exchange
    
    Returns:
        dict: Relatório de discrepâncias encontradas
    r<   h㈵>r   d   皙?r=   r   )quantidade_salvaquantidade_atual	diferenca
percentualu,   
🚨 DISCREPÂNCIAS DETECTADAS NA CARTEIRA:z:   (Quantidades salvas vs. quantidades atuais na exchange)u      • :z     - Salva: rK    z     - Atual: rL   u        - Diferença: rM    (rN   %)uF   
💡 SUGESTÃO: As quantidades ATUAIS serão usadas como referência.uU      Se quiser sincronizar forçadamente, as quantidades da exchange têm precedência.)r)   r   r0   r&   absmaxr?   roundr*   r,   items)r   rD   rE   discrepanciasrK   Zlimite_minimor   Z	qtd_salvaZ	qtd_atualZqtd_salva_dZqtd_atual_drM   Zpercentual_diffrC   r
   r
   r   verificar_discrepancia_carteira   s@    


"

rX   zpt_BR.UTF-8zPortuguese_Brazil.1252 configuracoes_balanceamento.jsonZapi_key Z
api_secretZapi_key_testnetZapi_secret_testnettestnetZ
moeda_baseUSDTcapital_inicial  Ztempo_ciclo   Ztempo_refresh_tela	timeframeZ5mvariacao_balanceamento       @ZcomissaorJ   rI   Zsaldo_minimo
   Zsaldo_minimo_usdtg      @Zcomprar_imediatamenteZreinvestir_ganhos_percentual2   reset_portfolio_ao_iniciarZaguardar_melhor_hora	portfoliozlog_balanceamento.logzportfolio_estado.jsoni  @r#   r   )ZmaxBytesZbackupCountr   z%(message)szAmerica/Sao_Pauloc               
   C   s   zAt  } |  }tt d }|| }t|dkr?tdt| d tt	j
d|d dd|dkr6dnd	  tj  |W S  ty\ } ztd
|  W Y d}~dS d}~ww )zHSincroniza o timestamp com o servidor da Binance para evitar erros -1021r^   u)   Desincronização de relógio detectada: msu    ⚠ AVISO: Relógio do PC está .1fzs r   Z	adiantadoZatrasadou*   Não foi possível sincronizar timestamp: N)ccxtbinanceZ
fetch_timeinttimerS   r*   r,   printr   YELLOWr   	RESET_ALLr/   )Zpublic_exchangeZserver_timeZ
local_timetime_offsetr2   r
   r
   r   sincronizar_timestamp_binance1  s   2rq   Zspoti N  )ZdefaultTypeZ
recvWindowtimeDifference)ZapiKeyZsecretZenableRateLimitoptionsz-Modo Testnet: ATIVADO (usando chaves testnet)zModo Testnet: DESATIVADOu*   Compra Imediata: ATIVADA (tolerância 10%)u,   Compra Imediata: DESATIVADA (tolerância 2%)u   Valor Mínimo de Operação: $.2fz
 (Binance)u   Proteção USDT: Mínimo $u    (não será gasto)u"   ✓ Exchange conectada com sucessou)   ✓ Mercados carregados (Exchange pronta)zFalha ao configurar exchange: c                 C   s6   t td}d| d|  }t| t| dS )u   Log e print simultâneos%d/%m/%Y %H:%M:%S[z] N)r   r@   rA   strftimer*   rC   rm   mensagem	timestampZmsg_completar
   r
   r   log_infox  s   
r{   c                 C   B   t td}d| d|  }t| ttj| t	j
  dS )zLog e print de erroru   rv   z] ERRO: N)r   r@   rA   rw   r*   r9   rm   r   ZREDr   ro   rx   r
   r
   r   log_erro     
r}   c                 C   r|   )zLog e print de avisoru   rv   z	] AVISO: N)r   r@   rA   rw   r*   r,   rm   r   rn   r   ro   rx   r
   r
   r   	log_aviso  r~   r   c                 C   r|   )zLog e print de sucessoru   rv   u   ] ✓ N)r   r@   rA   rw   r*   rC   rm   r   GREENr   ro   rx   r
   r
   r   log_sucesso  r~   r   c                 C   s  d}t |D ]x}zt| }|dp|d}|r!t|W   S dW   S  ty~ } zMt|}d|v s9d|v rb||d k rbtd|  d	|d  d
| d t a	t	tj
d< td W Y d}~q||d krrtd|  d|  W Y d}~ dS d}~ww dS )u:   Obtém o preço atual de um símbolo com retry automáticor#   lastcloseN-1021	Timestamp   zErro de timestamp ao obter  , resincronizando... (tentativa /)rr   r   u   Erro ao obter preço de r4   )rangeexchangefetch_tickerr)   r&   r/   r0   r   rq   rp   rs   rl   sleepr}   )symbolmax_tentativas	tentativatickerZpricer2   erro_strr
   r
   r   obter_preco_atual  s*   
 

r   c           	      C   s6  d}t |D ]}zGt| }|dp|dp|d}|du r@|dp*|d}|d}|r@|r@|d	kr@|| | d
 }|durKt|W   S dW   S  ty } z=t|}d|v scd|v r|||d k r|t attj	d< t
d W Y d}~q||d krtd|  d|  W Y d}~ dS d}~ww dS )uJ   Obtém a variação percentual de 24h de um símbolo com retry automáticor#   Z
percentageZchangeZchangePercentNr   r   r   r   rI   g        r   r   r   rr   r   u    Erro ao obter variação 24h de r4   )r   r   r   r)   r&   r/   r0   rq   rp   rs   rl   r   r}   )	r   r   r   r   ZvariacaoZclose_priceZ
open_pricer2   r   r
   r
   r   obter_variacao_24h  s2   

 

r   c                 C   s  d}t |D ]}z%t }|di }|| d}t|tr%t|W   S tt|W   S  ty } zQt|}d|v sAd|v rj||d k rjtd|  d|d  d	| d
 t	 a
t
tjd< td W Y d}~q||d krztd|  d|  tdW  Y d}~  S d}~ww dS )ua   Obtém saldo disponível de um ativo com retry automático (retorna Decimal para precisão total)r#   freer   r   r   r   z$Erro de timestamp ao obter saldo de r   r   r   rr   r   NzErro ao obter saldo de r4   )r   r   Zfetch_balancer)   r>   r0   r   r/   r   rq   rp   rs   rl   r   r}   )Zativor   r   Zbalancer   r"   r2   r   r
   r
   r   obter_saldo  s0   
 

r   c                 C   s*   i }| D ]}t |||< qt t|t< |S )u.   Obtém saldos de todas as moedas do portfólio)r   
MOEDA_BASE)rD   rE   r   r
   r
   r   obter_saldos_portfolio  s
   r   c              
   C   s   zU| t jvrdd|  dfW S t | }|dp|d}|d}|r)|dkr5dd|  d| d	fW S |d
u s=|dkrFdd|  dfW S dd|  d|dd|dfW S  tys } zdd|  dt| fW  Y d
}~S d
}~ww )u   
    Verifica se um par de trading está disponível e funcionando no testnet
    
    Returns:
        tuple: (está_disponível, info_diagnóstica)
    FzPar u9    não está na lista de símbolos disponíveis no testnetr   r   Z
baseVolumer   u#    não tem preço válido (último: r   Nz* tem volume zero - sem liquidez no testnetTu    OK - Preço: .8fz
, Volume: zErro ao verificar par r4   )r   symbolsr   r)   r/   r0   )r   r   Z
last_pricevolumer2   r
   r
   r   verificar_par_disponivel  s   


 $r   c                 C   sR   t |td}| D ]}||d}||d}|dkr&|r&|t || 7 }q
|S )u+   Calcula o valor total do portfólio em USDTr   )r&   r)   r   )rD   rE   precosvalor_totalr   r!   r    r
   r
   r   obter_valor_portfolio  s   r   c                 C   s   d}|r(d|v r(|d D ]}|d dv r||d 7 }q|d dv r'||d 8 }qd}| D ]"}|dkrN| |d}| |d}	|dkrN|	dkrN|t||	 7 }q,|| }
|
S )u  
    ✓ NOVO: Calcula o ganho REAL do portfólio baseado no histórico de trades
    
    Ganho Real = (Valor atual das moedas em USDT) - (Capital investido em moedas)
    NÃO inclui USDT congelado/residual
    
    Args:
        moedas: Lista de moedas do portfólio
        saldos: Dicionário com saldos atuais
        precos: Dicionário com preços atuais
        estado: Estado do portfólio com histórico_trades
    
    Returns:
        float: Ganho/Perda real em USDT (apenas das moedas compradas)
    r   historico_tradesr   )compra_inicialcompra_balanceamentocompra_ajuste_capitalr"   )venda_balanceamentovenda_ajuste_capitalr\   r)   r&   )rD   rE   r   r   Zcapital_investido_moedasZtradeZvalor_moedas_atualr   r!   r    Z
ganho_realr
   r
   r   calcular_ganho_real  s$   r   c           
   	   C   s   |r|r|r|rt ||||}ntd| t }tdkr't}d}dtdd}n3|td  }t| }|dkrL|| }	d|dd|ddtd	d
|	d}n|dk rXd|dd}nd}||||fS )uB  
    Calcula o limite de portfólio considerando reinvestimento parcial de ganhos
    
    Args:
        valor_portfolio_real: Valor total real do portfólio em USDT
        moedas: Lista de moedas (opcional, para cálculo de ganho real)
        saldos: Dicionário de saldos (opcional, para cálculo de ganho real)
        precos: Dicionário de preços (opcional, para cálculo de ganho real)
        estado: Estado do portfólio (opcional, para cálculo de ganho real com histórico)
    
    Returns:
        tuple: (valor_limite, ganho_total, ganho_reinvestido, status_msg)
        - valor_limite: Valor a usar para cálculos de compra/venda
        - ganho_total: Ganho total acumulado (REAL, baseado em trades)
        - ganho_reinvestido: Valor do ganho sendo reinvestido
        - status_msg: Mensagem de status para log
    r   z"Modo PROTETOR: Usando EXATAMENTE $rt   z (ganhos congelados)rI   zGanho Total: $z | Reinvestindo: $rQ   .0fz%) | Congelado: $zPerda Atual: $u    (portfólio em recuperação)u<   Sem ganhos/perdas ainda (portfólio em fase de acumulação))r   rT   CAPITAL_INICIALREINVESTIR_GANHOS_PERCENTUAL)
Zvalor_portfolio_realrD   rE   r   r   ganho_totalZvalor_limiteZganho_reinvestidoZ
status_msgZganho_congelador
   r
   r   calcular_limite_reinvestimentoB  s,   
r   c           	      C   sz   i }|dkr| D ]}d||< q|S | D ]'}| |d}| |d}|dkr6|r6t|| }|| d ||< qd||< q|S )u9   Calcula os percentuais atuais de cada moeda no portfólior   rI   r   )	rD   rE   r   r   percentuaisr   r!   r    valor_moedar
   r
   r   calcular_percentuais_atuaisp  s   

r   c                 C   s   t | dk r
| g fS t| }t |}|d }d| d }|| }|| }|| }|d|  }|d|  }	g }
g }t| D ]\}}||  krJ|	krRn n|
| q<|| q<|
|fS )u   
    Remove outliers usando o método Interquartile Range (IQR)
    
    Args:
        precos: lista de preços
    
    Returns:
        tuple: (preços filtrados sem outliers, índices dos outliers)
       r#   g      ?)lensorted	enumerateappend)r   Zsorted_precosnZq1_idxZq3_idxZq1Zq3ZiqrZlimite_inferiorZlimite_superiorZprecos_filtradosindices_outliersidxr    r
   r
   r   remover_outliers_iqr  s$   
r   c                 C   s   t | S )u   
    DESCONTINUADO: Use obter_melhores_precos_30dias() em vez disso.
    Mantido para compatibilidade com versões antigas.
    )obter_melhores_precos_30dias)rD   r
   r
   r   obter_melhores_precos_5dias  s   r   c           -         sn  i }zd}| D ]}zn| dt  }tj||dd}|r$t|dk r3td| dt| d W qt|dkr?|d	d
 n|}t|}dd |D }dd |D }t|\}	}
t|\}}t|
t|B }t|}|| }|dkry|| d nd}i }t|D ]2\}}||vr|d }tj	|d t
d}|d}||vrg ||< || |j|d |d d qt|}dddg g ddddg g ddddg g ddddg g ddddg g ddddg g dd | D ]\}}|sqdd td D }|D ]}|d! d" }|d kr
d#}|| | qi }i }| D ]*\}}|rCtd$d% |D t| }td&d% |D t| }|||< |||< q|rlt||jd'}  |  d(  d)7  < ||  D ]} |  d* |d!  q]|rt||jd'}! |! d+  d)7  < ||! D ]} |! d, |d!  qq|dkrt| d- W qt  fd.d/d'}"t  fd0d/d'}# |" d( }$ |# d+ }%|dkr|$| d nd}&|dkr|%| d nd}'d1d2 }(|( |" d* })|( |# d, }* |" d3 |)t|&d)|$d4 |# d3 |*t|'d)|%d4|||t|d)|d5tjt
d d6}+|+||< td7| d8 td9| d:| d;d| d<d= td>| d?|d<d= td@|+dA d!  dB|) dC|&d<dD|$ dE| dF tdG|+dH d!  dB|* dC|'d<dD|% dE| dF W q ty }, ztdI| dJ|,  W Y d
},~,qd
},~,ww |W S  ty }, ztdK|,  i W  Y d
},~,S d
},~,ww )Lu  
    Busca os melhores preços (máxima e mínima) dos últimos 30 dias (ou máximo disponível) para cada moeda
    usando dados OHLCV (Open, High, Low, Close, Volume) da exchange
    Remove outliers para análise de padrões de horário mais confiáveis
    
    Retorna análise consolidada sem detalhe dia a dia para maior confiabilidade.
    Com ~250+ candles (≈10-11 dias), a confiança dos padrões é muito boa.
    
    Returns:
        dict: {
            'moeda': {
                'melhor_hora_compra': { hora, confianca%, ocorrencias },
                'melhor_hora_venda': { hora, confianca%, ocorrencias },
                'analise': {
                    'total_registros': int (candles coletados),
                    'registros_validos': int (após remover outliers),
                    'total_outliers': int,
                    'percentual_outliers': float (%)
                },
                'timestamp': str (ISO 8601)
            }
        }
    Z1hr      )limit   zCandles insuficientes para z (precisa 200, tem r   iNc                 S      g | ]}|d  qS )r   r
   .0candler
   r
   r   
<listcomp>      z0obter_melhores_precos_30dias.<locals>.<listcomp>c                 S   r   )r#   r
   r   r
   r
   r   r     r   r   rI   r^   tzz%Y-%m-%dr#   r   )horalowhighz00:00-03:59)labeldias_vencedor_compradias_vencedor_vendahoras_comprahoras_vendaz04:00-07:59z08:00-11:59z12:00-15:59z16:00-19:59z20:00-23:59)r   r   r   r#   r   r_   c                 S   s   i | ]}|g qS r
   r
   )r   ir
   r
   r   
<dictcomp>  s    z0obter_melhores_precos_30dias.<locals>.<dictcomp>   r   r   r_   c                 s       | ]}|d  V  qdS )r   Nr
   r   cr
   r
   r   	<genexpr>"      z/obter_melhores_precos_30dias.<locals>.<genexpr>c                 s   r   )r   Nr
   r   r
   r
   r   r   #  r   )keyr   r   r   r   r   u   : Nenhum dia com dados válidosc                        |  d S )Nr   r
   xZgrupos_horasr
   r   <lambda><      z.obter_melhores_precos_30dias.<locals>.<lambda>c                    r   )Nr   r
   r   r   r
   r   r   =  r   c                 S   sP   | sdS t dd | D }|t|  }t|d }t|d }|dd|dS )u&   Calcula a hora média em formato HH:MMN/Ac                 s   s    | ]}|d  V  qdS )<   Nr
   )r   hr
   r
   r   r   M  r   zLobter_melhores_precos_30dias.<locals>.calcular_hora_media.<locals>.<genexpr>r   02drO   )sumr   rk   )Z
horas_listZtotal_minutosZmedia_minutosZhorasZminutosr
   r
   r   calcular_hora_mediaG  s   z9obter_melhores_precos_30dias.<locals>.calcular_hora_mediar   )r   
hora_media	confiancaZocorrencias)total_registrosregistros_validostotal_outlierspercentual_outliers
total_dias)melhor_hora_compramelhor_hora_vendaZanaliserz     rO   u       📊 Registros: z coletados | u    válidos (rh   rR   u       ⚠️  Outliers: z removidos (u       ✓ Faixa COMPRA:  r   u    | Hora Média: u    | Confiança: z% | Melhor em  de z diasu       ✓ Faixa VENDA:   r   zErro ao buscar dados de r4   u    Erro ao obter melhores preços: )r   r   Zfetch_ohlcvr   r   r   setr   r   fromtimestamprA   rw   r   hourrV   r   r   minr)   rT   rU   r@   rB   r{   r/   r}   )-rD   melhores_precosr`   r   r   Zcandlesr   ZhighsZlowsZhighs_filtradosZoutliers_highZlows_filtradosZoutliers_lowr   r   r   r   Zcandles_por_datar   r   rz   dtZdata_strr   Zcandles_diaZ
grupos_diaZ	grupo_idxZprecos_medios_compraZprecos_medios_vendaZcandles_grupoZpreco_medio_lowZpreco_medio_highZmelhor_compra_diaZmelhor_venda_diaZmelhor_grupo_compraZmelhor_grupo_vendar   r   Zconfianca_compraZconfianca_vendar   Zhora_media_compraZhora_media_vendadados_moedar2   r
   r   r   r     s   






"26r   c              
   C   sx   z t d t|}|r|| d< tt|  t dt| d | W S  ty; } ztd|  | W  Y d}~S d}~ww )u   
    Atualiza o arquivo de estado do portfólio com os melhores preços dos últimos 30 dias (ou máximo disponível)
    Incluindo análise de padrões de horário e detecção de outliers
    uP   Atualizando dados de melhores preços (até 30 dias com análise consolidada)...best_prices_30daysu9   ✓ Dados de melhores preços (30 dias) atualizados para z moedasu$   Erro ao atualizar melhores preços: N)r{   r   r   PORTFOLIO_STATE_FILEr   r/   r}   )r   rD   r   r2   r
   r
   r   #atualizar_melhores_precos_portfolio  s   
r   c                 C   s  zt | }|r|dkrtd|  d W dS |dkr |d }n|d }td| d	| d	|   td
|d td|d zt| |||ddi}ttd}|	dd}|	dd}|	dd}	|	dd}
td| d| d|	dd|
d |dkrtd| d td td|  d td |dd! td"|dd# W W dS |d$krtd%| d W W dS |d&krt
d'|dd	|  d(|  |W W S t
d)|dd	|  d(|  |W W S  ty } zt|}td*|  td+ zt| ||}ttd}|	dd}|	dd}|	dd}	|	dd}
td| d| d|	dd|
d |dkrPtd,| d td- W W Y d}~W dS |d&krdt
d.|dd	|  d(|  nt
d/|dd	|  d(|  |W W  Y d}~W S  ty } ztd0|   td1t|  W Y d}~W Y d}~W dS d}~ww d}~ww  ty } z!td2| d3|  d4|dd5|  td6t   W Y d}~dS d}~ww )7u   
    Executa uma ordem de compra ou venda (limit order)
    Limit orders são mais confiáveis no testnet que market orders
    r   u   Falha ao obter preço para u)   . Não será possível criar limit order.NbuygRQ?g\(\?z  Criando limit order: rP          Preço Atual: r   u       Preço Limite: timeInForceZGTCru   idr   statusZdesconhecidofilledamountz  ID: z | Status: z | Preenchida: r   Zexpiredu1     ⚠️ AVISO: Ordem expirou imediatamente (ID: r   u        Possíveis causas:z     1. Par u"    pode não ter liquidez no testnetz     2. Quantidade u    pode ser inválidau        3. Preço z fora do spreadZcanceledu6     ⚠️ AVISO: Ordem foi cancelada pela Binance (ID: sellu   ✓ Ordem de VENDA executada: z em u   ✓ Ordem de COMPRA executada: z  Limit order falhou: z(  Tentando market order como fallback...u+     ⚠️ Market order também expirou (ID: z7     Problema aparentemente com par/liquidez no testnetu'   ✓ Ordem de VENDA (market) executada: u(   ✓ Ordem de COMPRA (market) executada: z+  Ambas market e limit order falharam para z  Market error: zFalha ao executar ordem z para rQ   z): z  Rastreamento: )r   r}   r{   r   create_limit_orderr   r@   rA   rw   r)   r   r/   r0   r   Zcreate_market_order	traceback
format_exc)r   sider!   preco_atualpreco_limiteordemrz   Zorder_idr   r   r   Ze_limitr   Ze_marketr2   r
   r
   r   executar_ordem  s   
	$$

!"r  c                 C   s   t | dt  S )u   Aplica comissão à quantidader   )r&   COMISSAO)r!   r
   r
   r   aplicar_comissao  s   r	  c              	   C   sN   | t k rd| d| d| ddt dd	}d|fS dd| d| d	| dfS )
u%  
    Valida se o valor da operação atende ao mínimo da Binance ($5 USD/USDT)
    
    Args:
        valor_operacao: Valor da operação em USDT
        moeda: Símbolo da moeda (ex: BTC)
        tipo_operacao: 'compra' ou 'venda'
    
    Returns:
        tuple: (é_válido, mensagem)
    u   Operação de r   z BLOQUEADA: Valor $rt   u    é inferior ao mínimo de $z exigido pela BinanceFTz validada: $)VALOR_MINIMO_OPERACAO)Zvalor_operacaor   Ztipo_operacaory   r
   r
   r   validar_valor_operacao  s   r  c           	   
   C      zPd| vs|| d vrW dS | d | }d|vrW dS |d d }|d d }| d}t|dkrNt|d  d	d }t|d
  d	d }|||fW S W dS  tym } ztd| d|  W Y d}~dS d}~ww )u?  
    Extrai a melhor hora de compra do estado do portfólio
    
    Args:
        estado: Estado atual do portfólio
        moeda: Símbolo da moeda
    
    Returns:
        tuple: (hora_inicio, hora_fim, confianca) ou (None, None, 0) se não encontrar
        Exemplo: (8, 11, 60.5) para o período 08:00-11:59
    r   NNr   r   r   r   -r   r   rO   r   u(   Erro ao extrair horário de compra para r4   Nsplitr   rk   r/   r   	r   r   r   Zmelhor_horar   parteshora_iniciohora_fimr2   r
   r
   r   extrair_horario_compra  &   
r  c              
   C      zEd| vs|| d vrW dS | d | }d|vsd|d vr!W dS |d d }| d}t|dkrCt|d }t|d }||fW S W dS  tyb } ztd	| d
|  W Y d}~dS d}~ww )u  
    Extrai a hora média de compra do estado do portfólio
    
    Args:
        estado: Estado atual do portfólio
        moeda: Símbolo da moeda
    
    Returns:
        tuple: (hora_media, minuto_medio) ou (None, None) se não encontrar
        Exemplo: (9, 30) para 09:30
    r   NNr   r   rO   r   r   r   u+   Erro ao extrair hora média de compra para r4   Nr  r   r   r   Zhora_media_strr  r   Zminutor2   r
   r
   r   extrair_hora_media_compra7  $   

r  c           
      C      t || \}}}|du rd|  dfS tjtdj}||kr+||  ko'|kn  }n||kp2||k}|dd|dd}|rO|  d| d	|d
d}d|fS |dd}	|  d| d	|d
d|	 }d|fS )u  
    Verifica se a hora atual está dentro do melhor período de compra para a moeda
    
    Args:
        moeda: Símbolo da moeda
        estado: Estado atual do portfólio com best_prices_30days
    
    Returns:
        tuple: (está_no_horário_ideal, mensagem_info)
    NFu@   : Dados de melhor hora não disponíveis (análise em progresso)r   r   :00-:59u!   : ✓ HORÁRIO IDEAL de compra! (   , confiança: rh   rR   T:00u(   : ⏰ Aguardando melhor hora de compra (   %). Próxima às )r  r   r@   rA   r   )
r   r   r  r  r   
hora_atualesta_dentroperiodo_strry   Zproxima_hora_comprar
   r
   r   eh_horario_compra_idealW     r%  c           	      C   s   t || \}}}|du rdS tjtd}|j}|j}||  kr%|kr&dS  ||k r3|| d | }n
d| | d | }td|S )u   
    Calcula quantos minutos faltam até a melhor hora de compra
    
    Args:
        moeda: Símbolo da moeda
        estado: Estado atual do portfólio
    
    Returns:
        int: Minutos até a melhor hora (ou 0 se já está na melhor hora)
    Nr   r   r      )r  r   r@   rA   r   minuterT   	r   r   r  r  _agorar"  minuto_atual	tempo_ater
   r
   r   calcular_tempo_ate_melhor_hora{  s   
r.  c                 C     |du rd}t || \}}}t|| \}}|du r(t|  d dd|  dfS tjtd}|j}	|j}
t }d}d}z||krO||	  koK|kn  }n|	|kpV|	|k}|durp|d	 | |	d	 |
  }|dk ro|d
7 }nd}|rK|dur/|	|kr|
|kr|dur|dkrt	|  d|dd d}||d	 k rt | }||kr|d	 | }t	|  d|d	 dd|d	 dd|dd|dd
 |d }t
| ||d	 k st|  d|dd|dd|dd d|d	 |  dfW S t|  d|dd|dd|dd dd|  dfW S t|  d|dd|dd|dd dd|  d fW S t|  d|dd|dd|dd dd|  dfW S |dur_|dd!|dd|dd}nd"|dd#}|dur||krt|  d$|dd%| d& dd|  d'fW S t	|  d(| d d}	 tjtd}|j}	|j}
||kr||	  ko|kn  }n	|	|kp|	|k}|rt|d	 d)}t|  d*| d+|dd d||  d,fW S t | }|d	 }||krt|  d-| d. d||  d/fW S ||kr|| }t	|  d0|dd1| d2|dd3 |d4 }t
| q tyI } ztd5|  d6|  dd|  d7fW  Y d}~S d}~ww )8ua  
    Aguarda até a melhor hora de compra para a moeda usando hora média inteligente
    
    Args:
        moeda: Símbolo da moeda
        estado: Estado atual do portfólio
        tempo_maximo_minutos: Tempo máximo de espera em minutos (None = 30 min como padrão)
    
    Returns:
        tuple: (aguardou, tempo_esperado_minutos, mensagem)
    N   uM   : Análise de melhor hora não disponível - prosseguindo com compra imediataFr   u*   : Análise de melhor hora não disponívelr   rc   r     *   : Já está no período ideal, mas faltam r   #   min para hora média. Aguardando...   : Aguardando hora média... (rh   min decorridos,    min faltam até r   rO   r   x   u&   : ✓ Hora média de compra atingida (r  rR   T   : Hora média atingidau!   : ✓ Horário ideal de compra! (r     :59, confiança: u'   : Já está no horário ideal de comprau4   : ✓ Horário ideal de compra! (Passou hora média u<   : Já está no horário ideal de compra (passou hora média)   min até hora média (   próximo período é r   2   : ⏳ Próxima janela ideal está muito distante (min > z!min). Pulando compra neste ciclo.2   : Pulando - próximo horário ideal muito distantez': Aguardando melhor hora de compra... (r   u.   : ✓ Horário ideal de compra atingido após    min (confiança:    : Horário ideal atingido   : Tempo máximo de espera (z'min) atingido. Prosseguindo com compra.: Timeout de espera atingido: Aguardando (r   min, min restante)r   z"Erro ao aguardar melhor hora para r4   z*: Erro na espera - prosseguindo com compra)r  r  r   r   r@   rA   r   r(  rl   r{   r   r   rU   r/   r}   r   r   Ztempo_maximo_minutosr  r  r   r   Zminuto_mediar+  r"  r,  Ztempo_inicialZintervalo_verificacaoZproximo_logZesta_no_periodoZtempo_ate_mediaZtempo_decorrido_segundosZtempo_faltandoZtempo_ate_media_msgr#  Ztempo_decorrido_minutosZtempo_restanter2   r
   r
   r   aguardar_melhor_hora_compra  s   
6
&&&&



$
 rG  c           	   
   C   r  )u?  
    Extrai a melhor hora de venda do estado do portfólio
    
    Args:
        estado: Estado atual do portfólio
        moeda: Símbolo da moeda
    
    Returns:
        tuple: (hora_inicio, hora_fim, confianca) ou (None, None, 0) se não encontrar
        Exemplo: (14, 17, 55.2) para o período 14:00-17:59
    r   r  r   r   r   r  r   r   rO   r   u'   Erro ao extrair horário de venda para r4   Nr  r  r
   r
   r   extrair_horario_venda&  r  rH  c              
   C   r  )u  
    Extrai a hora média de venda do estado do portfólio
    
    Args:
        estado: Estado atual do portfólio
        moeda: Símbolo da moeda
    
    Returns:
        tuple: (hora_media, minuto_medio) ou (None, None) se não encontrar
        Exemplo: (15, 45) para 15:45
    r   r  r   r   rO   r   r   r   u*   Erro ao extrair hora média de venda para r4   Nr  r  r
   r
   r   extrair_hora_media_vendaI  r  rI  c           
      C   r  )u  
    Verifica se a hora atual está dentro do melhor período de venda para a moeda
    
    Args:
        moeda: Símbolo da moeda
        estado: Estado atual do portfólio com best_prices_30days
    
    Returns:
        tuple: (está_no_horário_ideal, mensagem_info)
    NFuI   : Dados de melhor hora de venda não disponíveis (análise em progresso)r   r   r  r  u    : ✓ HORÁRIO IDEAL de venda! (r  rh   rR   Tr   u'   : ⏰ Aguardando melhor hora de venda (r!  )rH  r   r@   rA   r   )
r   r   r  r  r   r"  r#  r$  ry   Zproxima_hora_vendar
   r
   r   eh_horario_venda_ideali  r&  rJ  c           	      C   s   t || \}}}|du rdS tjtd}|j}|j}||krB||  kr)|kr*dS  ||k r7|| d | }nd| | d | }n||ksJ||krLdS || d | }td|S )u   
    Calcula quantos minutos faltam até a melhor hora de venda
    
    Args:
        moeda: Símbolo da moeda
        estado: Estado atual do portfólio
    
    Returns:
        int: Minutos até a melhor hora (ou 0 se já está na melhor hora)
    Nr   r   r   r'  )rH  r   r@   rA   r   r(  rT   r)  r
   r
   r   $calcular_tempo_ate_melhor_hora_venda  s"   
rK  c                 C   r/  )8u  
    Aguarda até a melhor hora de venda para a moeda usando hora média inteligente
    Útil para retirada de capital e rebalanceamento com otimização de preço
    
    Args:
        moeda: Símbolo da moeda
        estado: Estado atual do portfólio
        tempo_maximo_minutos: Tempo máximo de espera em minutos (None = 30 min como padrão)
    
    Returns:
        tuple: (aguardou, tempo_esperado_minutos, mensagem)
    Nr0  uU   : Análise de melhor hora de venda não disponível - prosseguindo com venda imediataFr   u3   : Análise de melhor hora de venda não disponívelr   rc   r   r1  r2  r   r3  r4  rh   r5  r6  r   rO   r   r7  u%   : ✓ Hora média de venda atingida (r  rR   Tr8  u    : ✓ Horário ideal de venda! (r  r9  u&   : Já está no horário ideal de vendau3   : ✓ Horário ideal de venda! (Passou hora média u;   : Já está no horário ideal de venda (passou hora média)r:  r;  r   r<  r=  z min). Pulando venda neste ciclo.r>  z&: Aguardando melhor hora de venda... (r   u-   : ✓ Horário ideal de venda atingido após r?  r@  rA  z&min) atingido. Prosseguindo com venda.rB  rC  r   rD  rE  r   z+Erro ao aguardar melhor hora de venda para r4   z): Erro na espera - prosseguindo com venda)rH  rI  r   r   r@   rA   r   r(  rl   r{   r   r   rU   r/   r}   rF  r
   r
   r   aguardar_melhor_hora_venda  s   
6
&&&&



$
 rL  c               
   C   s@  zd} t | ddd}t|}W d   n1 sw   Y  |ddkrd|d< t | d	dd}tj||d
dd W d   n1 sEw   Y  ztjtr^t	t t
dt d W n ty{ } ztdt d|  W Y d}~nd}~ww t
d W dS W dS  ty } ztd|  W Y d}~dS d}~ww )u  
    ✓ NOVO: Desativa automaticamente o reset após ser executado com sucesso
    Evita rodar limpeza desnecessária no próximo ciclo
    - Desativa flag reset_portfolio_ao_iniciar na configuração
    - Deleta portfolio_estado.json para forçar recriação com valores corretos
    rY   r   r   r   Nre   TFr   r   r   u   ✓ Arquivo u    deletado para recriaçãou   ⚠ Não foi possível deletar r4   u8   ✓ Reset desativado automaticamente nas configuraçõesu2   ⚠ Não foi possível desativar reset na config: )r   r   r   r)   r   r5   r6   r7   r   remover   r/   r   )config_filefconfigr2   r
   r
   r   desativar_reset_apos_limpezaC  s8   
 rQ  c                 C   sb  t sdS td td td tdtdd dd	 | D }t| }d}d}| D ]}||d}||d}|d
kr|dkrt|| }td| d tdt|dd|  td|d td|d | dt }	z?|d }
t	|	d||
ddi}|rt
d t|}|d
k rtd| d ||7 }|d7 }ntd| dt|dd W q* ty } ztd| d|  W Y d}~q*d}~ww q*tt}|durt|nd}td|t }td td | d! td"|d td#|d td$td |d%kr$td&|dd' td( td)tdd* ntd+ td, t  |S )-u  
    ✓ NOVO: Vende todas as moedas residuais para limpar o portfólio
    Útil quando "reset_portfolio_ao_iniciar" está ativado
    
    Args:
        moedas: Lista de moedas do portfólio
    
    Returns:
        float: Saldo USDT total após limpar tudo (deve ser ~2000)
    r   z=
============================================================u;   🧹 MODO RESET ATIVADO - LIMPANDO PORTFÓLIO COMPLETAMENTE<============================================================u1   
📋 Objetivo: Resetar para capital inicial de $rt   z USDTc                 S       i | ]}|t | d t qS r   r   r   r   mr
   r
   r   r   w       z+limpar_moedas_residuais.<locals>.<dictcomp>rH   u   
🔄 Vendendo z
 residual:z
   Saldo: r   rP   u      Preço: $z   Valor: $r   gGz?r   r   ZIOCr   u      ✓ z vendido com sucesso!u      ⚠ Venda parcial de z	 (restam r   u      ✗ Erro ao vender r4   Nu   ✓ RESET CONCLUÍDO: z moedas vendidasz  Valor recuperado: $z  Saldo USDT final: $z  Capital Inicial: $rd   u   
  ⚠️ AVISO: Há $z em USDT residual!u3     Este valor NÃO foi reinvestido na fase anterior.u     O robô usará exatamente $z + reinvestimentos.u#     ✓ Portfólio limpo com sucesso!z=============================================================
)RESET_PORTFOLIO_AO_INICIARr   r{   r   r   r)   r&   r   r   r   rl   r   r   r   r/   r}   rT   rQ  )rD   r   rE   Ztotal_usdt_recuperadoZmoedas_vendidasr   rF   r    Zvalor_vendar   r  r  saldo_depoisr2   saldo_usdt_finalZsaldo_usdt_final_floatZsaldo_usdt_residualr
   r
   r   limpar_moedas_residuaisd  sv   

 
r\  c                     s  dd t D } dd t D }dd t D }tr(t| }td|d td tt}|rTtd	 t| }t	|| |}|rWt
d
 t
d t
d t
d t
d td |d|dd}t|d krt| }t
d t
d|d t
dtd t
d|d t
d t|d< t|d< d|d< tt |d< tt| td nt|d k r|t }	t
d t
d|d t
dtd t
d|	d t
d|	dd  t|d< t|d< d|d!< |	|d"< tt |d#< tt| td$ n7t|d< |dd%rtd& d%|d< |d!d%rtd' d%|d!< |dd%u s.|d!d%u r3tt| d(|vs=|d( sFt
d) t|| }t| }tt| | || fS t|   fd*d| D }
|
rt
d+t|
 d,d-|
  d.tt ttd%d%d|  g ||g d/}td0 t| }tt| | || fS d1tt ttd%d%dg |  ||g d/}td2 td3t d4t  td5d-|   td6|  td7|  td8 t| }tt| | || fS )9u!   Inicializa o estado do portfólioc                 S       g | ]}| d dr|d qS ativaTr   r)   rV  r
   r
   r   r     rX  z)inicializar_portfolio.<locals>.<listcomp>c                 S   &   i | ]}| d dr|d |d qS )r_  Tr   rN   r`  rV  r
   r
   r   r        & z)inicializar_portfolio.<locals>.<dictcomp>c                 S   ra  )r_  Tr   preco_comprar`  rV  r
   r
   r   r     rb  u$   Após reset: Capital disponível = $rt   r   u+   Carregando estado anterior do portfólio...uP   
⚠️ O robô detectou discrepâncias entre as quantidades salvas e as atuais.z   Isso pode ocorrer se:u&      • O robô foi parado abruptamenteu>      • Houve transações manuais na exchange durante a paradau;      • Problemas de sincronização com cálculos de ganhosuA   
   → Usando as quantidades ATUAIS da exchange como referênciacapital_rastreador]   r   rI   u&   
💰 INCREMENTO DE CAPITAL DETECTADO!u      • Capital Anterior: $u      • Capital Atual: $u      • Incremento: $uE      ⏰ Aguardando melhor hora de compra para investir novo capital...Tem_incremento_capitalZdata_incremento_capitalu3   ✓ Estado com incremento de capital SALVO no discou(   
💸 DIMINUIÇÃO DE CAPITAL DETECTADA!u      • Diminuição: $uL      ⏰ Iniciando retirada de capital - serão vendidas moedas para retirar $z...em_retirada_capitalvalor_retiradaZdata_retirada_capitalu5   ✓ Estado com diminuição de capital SALVO no discoFuI   ✓ Incremento de capital concluído! Voltando ao rebalanceamento normal.uG   ✓ Retirada de capital concluída! Voltando ao rebalanceamento normal.r   z>Atualizando dados de melhor hora de compra antes de iniciar...c                    s    g | ]}  |d dkr|qS )r   rH   r`  rV  Zsaldos_reaisr
   r   r   *  rX  u$   Portfólio detectado no testnet com z	 moedas: z, balanceamento)fasedata_inicior]   rd  re  rf  rg  moedas_compradasmoedas_pendentespercentuais_alvoprecos_comprar   u9   ✓ Fase de Balanceamento iniciada (portfólio existente)
construcaouD   ===================== NOVO PORTFÓLIO INICIADO =====================Capital Inicial: rP   u   Moedas no Portfólio: zPercentuais Alvo: u   Preços de Compra (entrada): rR  )PORTFOLIO_CONFIGrY  r\  r{   rl   r   r;   r   r   rX   r   r)   r   r   r@   rA   rB   r   r   r   rG   r   joincopyr   )rD   rn  ro  Zsaldo_finalZestado_existentesaldos_atuaisrW   rd  Z
incrementoZ
diminuicaoZmoedas_com_saldor   r
   rh  r   inicializar_portfolio  s   




 

rv  c           8      C   s  t d d| vs| d std t| |} t|}dd |D }|td}t|}|D ]}||d}||d}|dkrH|rH|t|| 7 }q,t d|d |dkratdkratd	td t d
|ddt  t||||| \}	}
}}t	}t
dkr|dkrt|trt|n|}td||	 }|dkrt	| }td|dd td|d |dkr|nt}| dg }g }| d }| d }|D ]}||d}||d}||d}|dkrt | dt|dd ||vr|| q||vrC|| tr|dkr|| | d }|dk}n d}nt|| \}}|}|s6|dkr6|| | d }|dk}|r|r||dd }|	| }|| dt  }d}|tk rr|}t}|| dt  }d}td|dd|dd |dkr{t|nt} t||d\}!}"td| | }#|!r|tkr|#|krtd | d! t d"|d t d#|d t d$|ddt  t d%t|d | d&t }$t|$\}%}&|%std'|$ d( td)|&  td*| d+ qt d,|&  tp| d-d}'|'r-t d. t|| \}(})}*|(d/u rtd0|*  q|(r%td0|*  nt d0|*  nt d1 t|}+t|$d2|},|,rtd t|}-|-|+krYtd3 td4 t|}-|-|+ }.|.dkrtd5t|.dd|  ||vry|| || d< | d6 tt  |d7|||d8 t!|d7||| n*td9| d: td;t|+dd| d<t|-dd|  td= td>|$ d? td q|!st|" qtd@| dA|ddB| ddC qtr|dkr|| | d }/| dD|/dEdF}0nB| dG}0n<t"| |\}1}2}3|1d/ur9tjtdHj#}4t$|| }5|1dIdJ|2dIdK}6| dL|6 dM|3dEdN|5dOdP|d	}0n| dQ}0t |0 q||vrM|| q|| dR< || d< t%|dkrntdS dT| dU< tt  | dV< t|}7t&t'||7 t(t'|  | S )WuU   
    Fase 1: Completa o portfólio comprando as moedas até os preços definidos
    u9   
========== FASE DE CONSTRUÇÃO DO PORTFÓLIO ==========r   QAtualizando dados de melhor hora de compra para respeitar AGUARDAR_MELHOR_HORA...c                 S   rS  rT  rU  rV  r
   r
   r   r   o  rX  z-fase_construcao_portfolio.<locals>.<dictcomp>r   zSaldo USDT atual: rt   u;   Testnet sem USDT. Usando capital inicial como referência: "   Valor Total do Portfólio (REAL): rP   rd   !   
🔒 MODO PROTETOR: Congelando $ em USDT residual+      Saldo mínimo protegido ajustado para: $rl  rn  ro  rH   u   : Já possui r   z em carteirarI   Tr_   r   F       ⚡ Valor ajustado de $ para $    (mínimo da Binance)compra
>>> Comprando  <<<r   u       Preço Alvo:     Valor:     Quantidade: r        ⚠️ Par #    não está disponível no testnet!       Pulando compra de     - par indisponível     ✓ re  u@     ⏰ Buscando melhor momento de compra para maximizar lucros...Nr   u9     → Compra imediata (aguardar_melhor_hora desabilitado)r   C     Saldo não mudou na primeira verificação, aguardando mais 2s...r   &   ✓ Compra verificada: Saldo aumentou r   r   rz   r   r   r    r!   r"      ✗ FALHA: Compra de &    não confirmada! Saldo não aumentou.	  Antes:  | Depois: uA     ⚠ AVISO: A Binance aceitou a ordem mas não creditou o saldo!u#     Possível causa: Problema no par z no testnetz Saldo insuficiente para comprar z
 (precisa z, tem r   u*   : Preço muito alto para compra imediata (rh   z% acima). Esperando melhora...u-   : Preço alvo não definido na configuraçãor   r   r  r  z$: Aguardando melhor hora de compra (r  z%). Faltam r   u    min. Preço: u0   : Análise de melhor hora não disponível aindarm  u7   PORTFÓLIO COMPLETO! Iniciando fase de balanceamento...ri  rj  Zdata_balanceamento_inicio))r{   r   r   r   r)   r   r&   r   r   SALDO_MINIMO_USDTr   r>   r   rT   r   COMPRAR_IMEDIATAMENTEr%  r  r
  r  r   r}   AGUARDAR_MELHOR_HORArG  r   r   r  rl   r   r   r@   rA   rB   r3   r  r   r.  r   rG   r   r   )8r   rD   rE   r   
saldo_usdtvalor_portfolior   r!   r    valor_portfolio_limiter   ganho_reinv	msg_ganhosaldo_usdt_minimo_protegidoZsaldo_usdt_floatusdt_residualZsaldo_para_comprarl  rm  rn  ro  r  Z
preco_alvorL   Zdiferenca_percentualZcondicao_compraZesta_no_melhor_horarioZmsg_horarioZpercentual_alvovalor_compravalor_ajustadovalor_compra_originalZsaldo_disponivel	eh_validomsg_validacaoZsaldo_livrer   par_disponivelinfo_pardeve_aguardaraguardoutempo_esperado	msg_temposaldo_antesr  rZ  diferenca_saldoZdiferenca_pctry   r  r  r   r"  r-  r$  ru  r
   r
   r   fase_construcao_portfolioc  s.  














	,

"


(




r  c           F   
      s  t d d vs d std t | t|}dd |D }t|||}|td}t|tr5t	|n|}t d|dd	t  t
|||| \}}}}	t d
|dd	t  t d|	  t}
tdkr|dkrt|trst	|n|}td|| }|dkrt| }
td|dd td|
d t d|
dd t||||} d }t d g }g }|D ]^}||d}||d}|| }t | d|dd|dd|dd |tkr||||||dd td| d q|t k r||t||||dd td| d q ddr dd}|td}t|tr/t	|n|}|| }|tkrtd  td!|d td" |D ]}|d#krUqL||d}||d}|t| kr|dkrt	|| }|tkrtt	||| d$t  }|dkr| d%t }t d&| d|d'd(t	|| d t d) t| \}}}|d*u rtd+|  qL|rtd+|  nt d+|  t|d,|}|rtd$ t|}|td}t|trt	|n|}|| }|tkr ntd- qL|td} t|d.d/ d0d1D ]j}!|!d2 }|!d3 }|!d4 }||d}"|"dkr|dkr|d5 | }#|#| d$t  }d}$|#tk ri|"dkri|#}%t}#|#| d$t  }d0}$td6|%dd7|#dd8 t|#|d9\}&}'|&rx|dkrx||"krxtd:| d; t d<|d' t d=|d' t d>|#dd	t   dd}(|(rt d? t| \}}}|d*u rtd+|  q|rtd+|  nt d+|  nt d@ t|})| d%t }t|d,|}|rvtd$ t|}*|*|)kr
tdA tdB t|}*|)|* }+|+dkrWtdCt	|+d'd	|  t| tr*t	| n| } | |#7 }  ddr9dDndE}, dF tt  ||,|||#dG t!||,|||# nt"dH| dI t"dJ|)d'd	| dK|*d'd	|  td$ q|&st|' qt|}|td}t|trt	|n|}t dL t dM|d t dNt#| dOdPdQ |D   t dRt#| dOdSdQ |D   g }-d}.|D ](}/|/d2 }|/d3 }|/d4 }|dkr|d5 | }0|-||||0dT |.|07 }.qt|-dUd/ d0d1}-t|trt	|n|}dV}1|.|kre|.dkrtd||
 |. nd}1tdW tdX|d tdY|
d tdZtd||
 d td[|.d td\|1d5 d]d |1dkrdtd^|1d5 d]d n-t d_ t dX|d t dY|
d t dZtd||
 d t d[|.d t d` |-D ]}2|2d2 }|2d3 }|2da }3|3|1 }0d}$|0tk r|0}4t}0d0}$td6|4dd7|0dd8 |dkra|tkra|0| d$t  }5t|0|db\}&}'|&r|0tkr||0t krtdc| d; t d<|d' t d=|5d' t d>|0dd	t dd|3dde | d%t }t$|\}6}7|6s;t"df| dg t"dh|7  tdi| dj qt dk|7   dld}8|8rxt dm t%| \}}}|d*u retd+|  q|rptd+|  nt d+|  nt dn t|})t|do|5}|rtd$ t|}*|*|)krtdA tdB t|}*|*|) }+|+dkrtdpt	|+d'd	|  t|trt	|n|}||08 } dldrdqndr}9 dF tt  ||9||5|0dG t!||9||5|0 nt"ds| dt t"dJ|)d'd	| dK|*d'd	|  td$ q|&st|' q|tkr2td+| du|ddvtdde q||0t k rYtd+| dw|0t ddx|dde tdy|0ddztd qtd+| d{ qt d| t|}d}d |D }t|||}:t
|:||| \};}<}=}=t||||;|D ]}|d}>||d}?t | d|>dd~t&|? de qt d|:dd	t  t d|;dd	t  t d|<dd	t   dldr fddQ|D }@|@rt|@nd}A|Adk rtd td|Add td d dl< nt d t d|Add  ddr dd}B|d#d}C|C|BkrItd td|Bd td|Cd td d d< d d< n6|B|C }D|BdkrX|C|B d5 nd}Et d t d|Bd t d|Cd t d|Ddd|Ed]d t d t't(|| t)t(   S )u   
    Fase 2: Balanceia o portfólio mantendo os percentuais definidos
    Vende moedas acima do percentual e compra moedas abaixo
    u:   
========== FASE DE BALANCEAMENTO DO PORTFÓLIO ==========r   rw  c                 S   rS  rT  rU  rV  r
   r
   r   r   f  rX  z0fase_balanceamento_portfolio.<locals>.<dictcomp>r   rx  rt   rP   u9   ⚠️  Valor Total para CÁLCULOS (COM REINVESTIMENTO): u   📊 rd   ry  rz  r{  u   🔒 PROTEÇÃO USDT: Mínimo $u    não será gastorn  u    
--- Análise de Percentuais ---r4   	% (Alvo: u   %) - Diferença: +.2f%)r   rM   Zpercentual_atualr    u     → z acima do alvo (venda)z abaixo do alvo (compra)rf  Frg  u$   
🔄 MODO RETIRADA DE CAPITAL ATIVOz   Faltam retirar: $z>   Vendendo moedas prioritariamente para completar retirada...r\   r   r   z  Vendendo r   z por $u?     ⏰ Aguardando melhor hora de venda para maximizar retorno...Nr   r   g      ?c                 S      | d S NrM   r
   r   r
   r
   r   r         z.fase_balanceamento_portfolio.<locals>.<lambda>T)r   reverser   r    rM   rI   r|  r}  r~  Zvendaz
>>> Vendendo r  r   r  r  u>     ⏰ Buscando melhor momento de venda para retirar capital...u-     → Venda imediata (rebalanceamento normal)r  r   u%   ✓ Venda verificada: Saldo diminuiu r   r   r   r  u   ✗ FALHA: Venda de u&    não confirmada! Saldo não diminuiu.r  r  u!   
🔍 ESTADO ATUAL DO PORTFÓLIO:u      • USDT em Caixa: $u      • Moedas a Comprar: u    → c                 S   r   r   r
   rV  r
   r
   r   r   O	  r   z0fase_balanceamento_portfolio.<locals>.<listcomp>u      • Moedas a Vender: c                 S   r   r  r
   rV  r
   r
   r   r   P	  r   )r   r    rM   valor_idealc                 S   r  r  r
   r   r
   r
   r   r   g	  r  g      ?u/   
💰 CÁLCULO DE COMPRAS (SALDO INSUFICIENTE):u      • USDT Disponível: $u      • Proteção USDT: $u"      • USDT Livre (pode gastar): $u      • Total Necessário: $u      • Fator de Redução: rh   uV   ⚠ Saldo insuficiente para completar todas as compras. Reduzindo proporcionalmente a u-   
💰 CÁLCULO DE COMPRAS (SALDO SUFICIENTE):u*      • Fator de Redução: 100% (saldo ok)r  r  r  z	 (Ideal: r   r  r  r  r  r  r  re  uE     ⏰ Buscando melhor momento de compra para investir novo capital...u.     → Compra imediata (rebalanceamento normal)r   r  r   r   r  r  u&   : ⛔ Compra bloqueada - Saldo USDT ($u   ) ≤ Proteção ($u6   : ⛔ Compra bloqueada - Saldo insuficiente (precisa $z, tem $u!          └─ USDT Necessário: $u    + Proteção: $u1   : Compra rejeitada por outro motivo (validação)z 
--- Resumo do Balanceamento ---c                 S   rS  rT  rU  rV  r
   r
   r   r   	  rX  z
% (Saldo: zValor Total (REAL): u   Valor Total (CÁLCULOS): z Ganho REAL (baseado em trades): c                    s,   g | ]}t |d  d |d  qS )r   rn  )rS   r)   rV  r   Zpercentuais_finaisr
   r   r   
  s   , rb   u&   
✅ INCREMENTO DE CAPITAL CONCLUÍDO!u"      Desvio máximo de percentuais: zC   Voltando ao rebalanceamento normal (sem aguardar melhor hora)...u*   
⏳ Incremento de capital em progresso...z% (alvo: < 2.0%)u$   
✅ RETIRADA DE CAPITAL CONCLUÍDA!z   Valor retirado: $u      USDT disponível: $z(   Voltando ao rebalanceamento normal...u(   
⏳ Retirada de capital em progresso...z   Retirada solicitada: $u      USDT já retirado: $z   Faltando retirar: $rQ   u   % concluído)uC      O robô continuará vendendo moedas para completar a retirada...)*r{   r   r   r   r   r)   r   r>   r   r&   r   r  r   rT   r   VARIACAO_BALANCEAMENTOr   rS   r
  r   r  rL  r   r  rl   r   r   r  r   r   r@   rA   rB   r3   r}   r   r   rG  r0   rG   r   r   )Fr   rD   rE   r   r  Zsaldo_usdt_atualr  r   r  r  r  Zsaldo_usdt_atual_floatr  Zpercentuais_atuaisrn  Zmoedas_vendaZmoedas_comprar   Z	pct_atualpct_alvorM   rg  Zvalor_ainda_faltar!   r    r   Zquantidade_vendar   r  r  r  r  Zsaldo_usdt_antesZ
item_vendarL   Zvalor_excessor  Zvalor_excesso_originalr  r  Zdeve_aguardar_vendar  rZ  r  Z
tipo_vendaZcompras_planejadasZtotal_usdt_necessarioZitem_comprar  Zfator_reducaor  r  r  Zquantidade_comprar  r  r  Ztipo_compraZvalor_portfolio_finalZvalor_portfolio_limite_finalZganho_finalr*  Z	pct_finalZsaldo_moedaZdesviosZdesvio_maximoZvalor_retirada_solicitadoZ
usdt_atualZusdt_faltandoZpercentual_concluidor
   r  r   fase_balanceamento_portfolioX  sv  
&





&








	$
""

 


 




	$

$$$




r  c               
   C   sb  zt t} | rt| tstd W dS dd tD }t|}dd |D }t|||}t||||}dd |D }t	| |} || d< t
t | d	< || d
< tt|| tt|  td td td td| dd   td| dd  td| dd dt  td|ddt  | dd}|dkrtd|| ddt  td|| d d dd td  |D ]F}||d}	||d}
|
rt|	|
 nd}||d}| d!i |d}t| d"t|	d#d$d%t|d&d$|d'd(|dd)  qtd* | W S  ty0 } ztd+|  t  W Y d}~dS d}~ww ),u(   Exibe relatório detalhado do portfóliou*   Portfólio não inicializado ou corrompidoNc                 S   r]  r^  r`  rV  r
   r
   r   r   B
  rX  z'relatorio_portfolio.<locals>.<listcomp>c                 S   rS  rT  rU  rV  r
   r
   r   r   D
  rX  z'relatorio_portfolio.<locals>.<dictcomp>c                 S   rS  rT  )r   r   rV  r
   r
   r   r   I
  rX  Zprecos_atuaisZtimestamp_precosvariacoes_24hG
======================================================================u   RELATÓRIO DO PORTFÓLIOF======================================================================zFase: rj  Zdesconhecidau   Data de Início: rk  r   rq  r]   r   rP   zValor Atual: rt   zGanho/Perda: r  z	Ganho %: r   rI   r  zF----------------------------------------------------------------------rn  z: Saldo=z>16z | zValor: z12.2fz6.2fr  rR   zG======================================================================
u   Erro ao exibir relatório: )r;   r   r>   dictr   rr  r   r   r   r   r   r@   rA   rB   rG   r   r{   r)   upperr   r&   r0   r/   r}   r  	print_exc)r   rD   rE   r   r  r   r  Zcapitalr   rF   r    r"   Zpctr  r2   r
   r
   r   relatorio_portfolio:
  s\   

 r  c               
   C   s  t d t d t d t \} }d}d}z	 trNt rNt }t d t d |r?t d|d  t d	|d
  t d t d t  W dS |d7 }|d7 }z3| d dkrct| |} n| d dkrnt| |} |t	kr{t
 }|ry|} d}t dt d tt W n% ty } ztd| d|  t  tt W Y d}~nd}~ww q ty   t d t
  Y dS  ty } ztd|  t  W Y d}~dS d}~ww )u   Função principalr  u/   ROBÔ DE BALANCEAMENTO DE PORTFÓLIO - INICIADOr  r   Tu    ⏹️  SINAL DE PARADA RECEBIDOzSolicitado por: Z
pedido_porzTimestamp: rz   u   Encerrando robô gracefully...r   rj  rp  ri  u   
Próximo ciclo em z segundos...zErro no ciclo r4   Nu!   
Robô interrompido pelo usuáriozErro fatal: )r{   rv  controlador_stopZ
deve_pararZobter_info_paradar)   Zlimpar_stopr  r  TEMPO_REFRESHr  TEMPO_CICLOrl   r   r/   r}   r  r  KeyboardInterrupt)r   rD   Zcontador_cicloZcontador_relatoriorC   Zestado_atualizador2   r
   r
   r   main
  s`   

%r  __main__)NNNN)N)__doc__ri   ZpandasZpdrl   r*   Zlogging.handlersr   r   localer5   r  r   r   pytzZcoloramar   r   r   Zdecimalr   r  ImportErrorr'   r%   r,   Zconfig_sqlite_apir	   ZCONFIG_API_DISPONIVELr   r   r3   r;   rG   rX   	setlocaleLC_ALLErrorrP  r)   ZAPI_KEYZ
API_SECRETZAPI_KEY_TESTNETZAPI_SECRET_TESTNETZTESTNETr   r&   r   rk   r  r  Z	TIMEFRAMEr  r  ZSALDO_MINIMOr  r
  r  r   rY  r  rr  ZLOG_FILENAMEr   	getLoggerloggersetLevelINFOhandlershandlerremoveHandlerZrotating_handler	Formatter	formattersetFormatter
addHandlerrA   rq   rp   Z	chave_apiZchave_secretarj   r   Zset_sandbox_moderC   rm   Zload_marketsr   ro   r/   r2   r9   r{   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r	  r  r  r  r%  r.  rG  rH  rI  rJ  rK  rL  rQ  r\  rv  r  r  r  r  __name__r
   r
   r
   r   <module>   s`  :,;











 
*.' Pe# $
! # $
+ !`   v   eF
7
