o
    `ia                    @   st  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 e  dd Zdd	 Zd
d Zz	e	e	jd W n e	jyt   z	e	e	jd W n
 e	jyq   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"e#eddZ$e#eddZ%eddZ&e!edd Z'e!ed!d"d# Z(e!ed$d%Z)d&Z*ed'dZ+ed(dZ,ed)g Z-d*Z.d+Z/e0 Z1e12ej3 e1j4dd D ]Z5e16e5 qee.d,d-d.d/Z7e72ej3 e8d0Z9e7:e9 e1;e7 e<d1Z<d2d3 Z=e= a>er7eZ?eZ@neZ?eZ@eAe?e@d4d5d6t>d7d8ZBer[eBCd4 eDd9 eEd9 n	eDd: eEd: e+rqeDd; eEd; n	eDd< eEd< eDd=e*d>d? eEd=e*d>d? zeBF  eDd@ eEejGdA ejH  W n" eIy ZJ zeKdBeJ  eEdBeJ  W Y dZJ[JndZJ[Jww dCdD ZLdEdF ZMdGdH ZNdIdJ ZOdKdL ZPdMdN ZQdOdP ZRdQdR ZSdSdT ZTdUdV ZUdWdX ZVdYdZ ZWd[d\ ZXd]d^ ZYd_d` ZZdadb Z[dcdd Z\dedf Z]dgdh Z^didj Z_dxdkdlZ`dmdn Zadodp Zbdqdr Zcdsdt Zddudv Zeefdwkr8ee  dS dS )yu   
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Stylec                 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file r   N/var/www/html/robo.fernandesemelo.com.br/balanceamento20/robo_balanceamento.pycarregar_configuracoes   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_portfolio   s   "r   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   loggingwarningJSONDecodeErrorerror	Exception)r   r   dataer   r   r   carregar_estado_portfolio#   s(   
"r&   zpt_BR.UTF-8zPortuguese_Brazil.1252z configuracoes_balanceamento.jsonZapi_key Z
api_secretZapi_key_testnetZapi_secret_testnettestnetFZ
moeda_baseZUSDTcapital_inicial  Ztempo_ciclo   Ztempo_refresh_tela	timeframeZ5mvariacao_balanceamentog       @Zcomissaog?d   Zsaldo_minimo
   g      @Zcomprar_imediatamenteZaguardar_melhor_hora	portfoliozlog_balanceamento.logzportfolio_estado.jsoni  @   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timeabsr   r    printr   YELLOWr   	RESET_ALLr#   )Zpublic_exchangeZserver_timeZ
local_timetime_offsetr%   r   r   r   sincronizar_timestamp_binancev   s   2r=   TZ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"   ✓ 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   nowtimezonestrftimer   infor9   mensagem	timestampZmsg_completar   r   r   log_info   s   
rJ   c                 C   B   t td}d| d|  }t| ttj| t	j
  dS )zLog e print de errorA   rB   z] ERRO: N)r   rC   rD   rE   r   r"   r9   r   ZREDr   r;   rG   r   r   r   log_erro      
rL   c                 C   rK   )zLog e print de avisorA   rB   z	] AVISO: N)r   rC   rD   rE   r   r    r9   r   r:   r   r;   rG   r   r   r   	log_aviso   rM   rN   c                 C   rK   )zLog e print de sucessorA   rB   u   ] ✓ N)r   rC   rD   rE   r   rF   r9   r   GREENr   r;   rG   r   r   r   log_sucesso   rM   rP   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áticor1   lastcloseN-1021	Timestamp   zErro de timestamp ao obter  , resincronizando... (tentativa /)r>   r   u   Erro ao obter preço de r   )rangeexchangefetch_tickergetfloatr#   strrN   r=   r<   r?   r7   sleeprL   )symbolmax_tentativas	tentativatickerZpricer%   erro_strr   r   r   obter_preco_atual   s*   
 

re   c                 C   s   d}t |D ]p}zt }|di }t|| dW   S  tyv } zMt|}d|v s1d|v rZ||d k rZtd|  d|d  d	| d
 t a	t	tj
d< td W Y d}~q||d krjtd|  d|  W Y d}~ dS d}~ww dS )u:   Obtém saldo disponível de um ativo com retry automáticor1   freer   rS   rT   rU   z$Erro de timestamp ao obter saldo de rV   rW   rX   r>   r   NzErro ao obter saldo de r   g        )rY   rZ   Zfetch_balancer\   r]   r#   r^   rN   r=   r<   r?   r7   r_   rL   )Zativora   rb   Zbalancerf   r%   rd   r   r   r   obter_saldo   s*    

rg   c                 C   s*   i }| D ]}t |||< qt t|t< |S )u.   Obtém saldos de todas as moedas do portfólio)rg   
MOEDA_BASE)moedassaldosmoedar   r   r   obter_saldos_portfolio  s
   rl   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 testnetrQ   rR   Z
baseVolumer   u#    não tem preço válido (último: rX   Nz* tem volume zero - sem liquidez no testnetTu    OK - Preço: .8fz
, Volume: zErro ao verificar par r   )rZ   symbolsr[   r\   r#   r^   )r`   rc   Z
last_pricevolumer%   r   r   r   verificar_par_disponivel  s   


 $rp   c                 C   sJ   | td}| D ]}| |d}| |d}|dkr"|r"||| 7 }q|S )u+   Calcula o valor total do portfólio em USDTr   )r\   rh   )ri   rj   precosvalor_totalrk   
quantidadeprecor   r   r   obter_valor_portfolio+  s   ru   c           	      C   sv   i }|dkr| D ]}d||< q|S | D ]%}| |d}| |d}|dkr4|r4|| }|| d ||< qd||< q|S )u9   Calcula os percentuais atuais de cada moeda no portfólior   r.   r\   )	ri   rj   rq   rr   percentuaisrk   rs   rt   Zvalor_moedar   r   r   calcular_percentuais_atuais5  s   

rx   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)
       r1   g      ?)lensorted	enumerateappend)rq   Zsorted_precosnZq1_idxZq3_idxZq1Zq3ZiqrZlimite_inferiorZlimite_superiorZprecos_filtradosindices_outliersidxrt   r   r   r   remover_outliers_iqrH  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)ri   r   r   r   obter_melhores_precos_5diaso  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1hrW      )limit   zCandles insuficientes para z (precisa 200, tem rX   iNc                 S      g | ]}|d  qS )r   r   .0candler   r   r   
<listcomp>      z0obter_melhores_precos_30dias.<locals>.<listcomp>c                 S   r   )r1   r   r   r   r   r   r     r   r   r.   r*   tzz%Y-%m-%dr1   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   rU   r   r1   ry   r+   c                 S   s   i | ]}|g qS r   r   )r   ir   r   r   
<dictcomp>  s    z0obter_melhores_precos_30dias.<locals>.<dictcomp>   r   ry   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   rU   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     r   zLobter_melhores_precos_30dias.<locals>.calcular_hora_media.<locals>.<genexpr>r   02d:)sumrz   r6   )Z
horas_listZtotal_minutosZmedia_minutosZhorasZminutosr   r   r   calcular_hora_media  s   z9obter_melhores_precos_30dias.<locals>.calcular_hora_mediar   )r   Z
hora_media	confiancaZocorrencias)total_registrosregistros_validostotal_outlierspercentual_outliers
total_dias)melhor_hora_compramelhor_hora_vendaZanaliserI     r   u       📊 Registros: z coletados | u    válidos (r3   %)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 r   u    Erro ao obter melhores preços: )rh   rZ   Zfetch_ohlcvrz   rN   r   setr|   r   fromtimestamprD   rE   r}   houritemsrY   r   minr\   maxroundrC   	isoformatrJ   r#   rL   )-ri   melhores_precosr,   rk   r`   Zcandlesr   ZhighsZlowsZhighs_filtradosZoutliers_highZlows_filtradosZoutliers_lowr   r   r   r   Zcandles_por_datar   r   rI   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_moedar%   r   r   r   r   v  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)rJ   r   r   PORTFOLIO_STATE_FILErz   r#   rL   )r   ri   r   r%   r   r   r   #atualizar_melhores_precos_portfolioE  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:         Preço Atual: rm   u       Preço Limite: ZtimeInForceZGTCrA   idr   statusZdesconhecidofilledamountz  ID: z | Status: z | Preenchida: rW   Zexpiredu1     ⚠️ AVISO: Ordem expirou imediatamente (ID: rX   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 z (z): z  Rastreamento: )re   rL   rJ   rZ   Zcreate_limit_orderr   rC   rD   rE   r\   rP   r#   r^   rN   Zcreate_market_order	traceback
format_exc)r`   siders   preco_atualZpreco_limiteordemrI   Zorder_idr   r   r   Ze_limitrd   Ze_marketr%   r   r   r   executar_ordemZ  s   
	$$

!"r   c                 C   s   | dt   S )u   Aplica comissão à quantidaderU   )COMISSAO)rs   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 $r@   u    é inferior ao mínimo de $z exigido pela BinanceFTz validada: $)VALOR_MINIMO_OPERACAO)Zvalor_operacaork   Ztipo_operacaorH   r   r   r   validar_valor_operacao  s   r   c           	   
   C   s   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   r   rU   u(   Erro ao extrair horário de compra para r   N)splitrz   r6   r#   rN   )	r   rk   r   Zmelhor_horar   Zparteshora_iniciohora_fimr%   r   r   r   extrair_horario_compra  s&   
r   c           
      C   s   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   z:00-z:59u!   : ✓ HORÁRIO IDEAL de compra! (u   , confiança: r3   r   Tz:00u(   : ⏰ Aguardando melhor hora de compra (u   %). Próxima às )r   r   rC   rD   r   )
rk   r   r   r   r   
hora_atualZesta_dentroZperiodo_strrH   Zproxima_hora_comprar   r   r   eh_horario_compra_ideal  s   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   rC   rD   r   minuter   )	rk   r   r   r   _Zagorar   Zminuto_atualZ	tempo_ater   r   r   calcular_tempo_ate_melhor_hora  s   
r   c              
   C   sx  |du rd}t || \}}}|du r!t|  d dd|  dfS t }d}d}d}	zl	 t| |\}
}|
rSt|d	 d
}|  d| d|dd}t| d||fW S t | }|d	 }||krtt|  d| d d||  dfW S ||	krt| |}t|  d|dd| d| d |d }	t| q- t	y } zt
d|  d|  dd|  dfW  Y d}~S d}~ww )uA  
    Aguarda até a melhor hora de compra para a moeda
    
    Args:
        moeda: Símbolo da moeda
        estado: Estado atual do portfólio
        tempo_maximo_minutos: Tempo máximo de espera em minutos (None = 5 min como padrão)
    
    Returns:
        tuple: (aguardou, tempo_esperado_minutos, mensagem)
    Nr+   uM   : Análise de melhor hora não disponível - prosseguindo com compra imediataFr   u*   : Análise de melhor hora não disponívelr/   Tr   rU   u.   : ✓ Horário ideal de compra atingido após u    min de espera (confiança: r3   r   u   : Tempo máximo de espera (z( min) atingido. Prosseguindo com compra.z: Timeout de espera atingidoz: Aguardando melhor hora... (rW   z min, u    min até a janela ideal)r   z"Erro ao aguardar melhor hora para r   z*: Erro na espera - prosseguindo com compra)r   rN   r7   r   r   rP   r   rJ   r_   r#   rL   )rk   r   tempo_maximo_minutosr   r   r   Ztempo_inicialZtempo_decorrido_segundosZintervalo_verificacaoZproximo_logZ
esta_idealmsgZtempo_esperado_minZmensagem_sucessoZtempo_decorrido_minutost
   tempo_atér%   r   r   r   aguardar_melhor_hora_compra@  sD   
"
r   c               	      s6  dd t D } dd t D }dd t D }tt}|r#td || fS t|   fdd| D }|r[tdt| d	d
|  dt	t
 t|  g ||g d}td || fS dt	t
 tg |  ||g d}td tdt dt  tdd
|   td|  td|  td || fS )u!   Inicializa o estado do portfólioc                 S       g | ]}| d dr|d qS ativaTrk   rv   r   mr   r   r   r   ~       z)inicializar_portfolio.<locals>.<listcomp>c                 S   &   i | ]}| d dr|d |d qS )r   Trk   
percentualrv   r   r   r   r   r        & z)inicializar_portfolio.<locals>.<dictcomp>c                 S   r   )r   Trk   preco_comprarv   r   r   r   r   r     r   u+   Carregando estado anterior do portfólio...c                    s    g | ]}  |d dkr|qS )r   h㈵>rv   r   Zsaldos_reaisr   r   r     r   u$   Portfólio detectado no testnet com z	 moedas: z, balanceamento)fasedata_inicior)   moedas_compradasmoedas_pendentespercentuais_alvoprecos_comprahistorico_tradesu9   ✓ Fase de Balanceamento iniciada (portfólio existente)
construcaouD   ===================== NOVO PORTFÓLIO INICIADO =====================Capital Inicial: r   u   Moedas no Portfólio: zPercentuais Alvo: u   Preços de Compra (entrada): z<============================================================)PORTFOLIO_CONFIGr&   r   rJ   rl   rN   rz   joinr   rC   rD   r   CAPITAL_INICIALcopyrh   )ri   r   r   Zestado_existenteZmoedas_com_saldor   r   r   r   inicializar_portfolio|  sL   
r   c           %   
   C   s  t d t|}dd |D }|td}|}|D ]}||d}||d}|dkr3|r3||| 7 }q|dkr:|nt}	t d|d |dkrTtdkrTtdtd t d|dd	t  | d
g }
g }| d }| d }|D ]}||d}||d}||d}|dkrt | d|dd |
| qq||
vrY|| tr|dkr|| | d }|dk}nd}nd}|dkr||d|  k}nd}|r#|r#||dd }|| }|| dt  }|dkr|nt}t	||d\}}|r
|t
kr
||kr
td| d t d|d t d|d t d|dd	t  t d|d | dt }t|\}}|sVtd| d  td!|  td"| d# qqt d$|  trt d% t|| d&d'\}}}|rytd(|  nt d(|  nt d) t|}t|d*|} | r	td t|}!|!|krtd+ td, t|}!|!| }"|"dkrtd-|"dd	|  |
| |
| d
< | d. tt |d/|||d0 n&td1| d2 td3|dd	| d4|!dd	|  td5 td6| d7 td qq|st| qqtd8| d9|dd:|dd; qq|dkrO|| | d }#tr=| d<|#d=d>}$n| d?|dd@|ddA|#d=dB}$n| dC}$t |$ qq|
| qq|| dD< |
| d
< t|dkrtdE dF| dG< tt | dH< tt|  | S )IuU   
    Fase 1: Completa o portfólio comprando as moedas até os preços definidos
    u9   
========== FASE DE CONSTRUÇÃO DO PORTFÓLIO ==========c                 S       i | ]}|t | d t qS rW   re   rh   r   r   r   r   r     r   z-fase_construcao_portfolio.<locals>.<dictcomp>r   zSaldo USDT atual: r@   u;   Testnet sem USDT. Usando capital inicial como referência:    Valor Total do Portfólio: r   r   r   r   r   u   : Já possui rm   z em carteirar.   2   Tg{Gz?rU   Fcompra
>>> Comprando  <<<r   u       Preço Alvo:     Valor:     Quantidade: rW        ⚠️ Par #    não está disponível no testnet!       Pulando compra de     - par indisponível     ✓ @     ⏰ Buscando melhor momento de compra para maximizar lucros...r+   r   r   9     → 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   Zcompra_inicialrI   rk   Ztiport   rs   valor   ✗ 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 rX   u*   : Preço muito alto para compra imediata (r3   z% acima). Esperando melhora...u#   : Aguardando preço melhor (Atual: z	 | Alvo: u    | Diferença: +r   u-   : Preço alvo não definido na configuraçãor   u7   PORTFÓLIO COMPLETO! Iniciando fase de balanceamento...r   r   Zdata_balanceamento_inicio)rJ   rl   r\   rh   r   rN   r}   COMPRAR_IMEDIATAMENTEr   r   SALDO_MINIMOrp   rL   AGUARDAR_MELHOR_HORAr   rP   rg   r   r7   r_   r   rC   rD   r   rz   r   r   )%r   ri   rj   rq   Z
saldo_usdtvalor_portfoliork   rs   rt   Zsaldo_para_comprar   r   r   r   r   Z
preco_alvoquantidade_atualZdiferenca_percentualZcondicao_compraZ
toleranciaZpercentual_alvovalor_compraZsaldo_disponivel	eh_validomsg_validacaor`   par_disponivelinfo_paraguardoutempo_esperado	msg_temposaldo_antesr   saldo_depoisdiferenca_saldoZdiferenca_pctrH   r   r   r   fase_construcao_portfolio  s   










	$

"
$


r,  c           *   
   C   s  t d t|}dd |D }t|||}t d|ddt  t||||}| d }t d g }g }|D ]]}	||	d	}
||	d	}|
| }t |	 d
|
dd|dd|dd |tkru||	||
||	d	d td|	 d q5|t k r||	t	||
||	d	d td|	 d q5|td	}t
|dd ddD ]}|d }	|d }|d }||	d	}|d	kr|d	kr|d | }|| dt  }t||	d\}}|r|d	kr||krtd|	 d t d|d  t d!|d  t d"|ddt  t|	}|	 d#t }t|d$|}|rtd t|	}||kr5td% td& t|	}|| }|d	kratd'|d d|	  ||7 }| d( tt |	d)|||d* ntd+|	 d, td-|d d|	 d.|d d|	  td q|st| qt|}|td	}g }d	}|D ](}|d }	|d }|d }|d	kr|d | }||	|||d/ ||7 }qt
|d0d dd}d1}||kr|d	krtd	|t | nd	}|d	krtd2|d d3d |D ]L} | d }	| d }| d4 }!|!| }|tk rtd5|	 d6|dd7td q|d	kr@|tkr@|| dt  }"t||	d8\}}|r9|tkr9||kr9td9|	 d t d|d  t d!|"d  t d"|ddt d:|!dd; |	 d#t }t|\}#}$|#std<| d= td>|$  td?|	 d@ qt dA|$  trt dB t|	| dCdD\}%}&}'|%rtd5|'  nt d5|'  nt dE t|	}t|dF|"}|r7td t|	}||krtd% td& t|	}|| }|d	krtdG|d d|	  ||8 }| d( tt |	dH||"|d* ntdI|	 dJ td-|d d|	 d.|d d|	  td q|s@t| qt dK t|}dLd |D }t|||}(t||||(})|D ]}	t |	 d
|)|	d	ddM||	d	d d; q`t dN|(ddt  tt|  | S )Ou   
    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 ==========c                 S   r  r  r  r   r   r   r   r   i  r   z0fase_balanceamento_portfolio.<locals>.<dictcomp>r  r@   r   r   u    
--- Análise de Percentuais ---r   r   	% (Alvo: u   %) - Diferença: +.2f%)rk   	diferencaZpercentual_atualrt   u     → z acima do alvo (venda)z abaixo do alvo (compra)c                 S      | d S Nr0  r   r   r   r   r   r         z.fase_balanceamento_portfolio.<locals>.<lambda>T)r   reverserk   rt   r0  r.   rU   Zvendaz
>>> Vendendo r  r   rm   r
  r	  rW   r   r  r   u%   ✓ Venda verificada: Saldo diminuiu r   Zvenda_balanceamentor  u   ✗ FALHA: Venda de u&    não confirmada! Saldo não diminuiu.r  r  )rk   rt   r0  valor_idealc                 S   r1  r2  r   r   r   r   r   r     r3  g      ?uW   
⚠ Saldo insuficiente para completar todas as compras. Reduzindo proporcionalmente a r3   r5  r   z: Valor ajustado $u    abaixo do mínimo $r  r  z	 (Ideal: rX   r  r  r  r  r  r  r  r1   r  r  r   r  Zcompra_balanceamentor  r  z 
--- Resumo do Balanceamento ---c                 S   r  r  r  r   r   r   r   r   M  r   z
% (Saldo: zValor Total Final: )rJ   rl   ru   rh   rx   r\   VARIACAO_BALANCEAMENTOr}   rN   r8   r{   r   r   rg   r   r7   r_   rP   r   rC   rD   r   rL   r   r  r   rp   r  r   r   r   )*r   ri   rj   rq   r  Zpercentuais_atuaisr   Zmoedas_vendaZmoedas_comprark   Z	pct_atualpct_alvor0  Zsaldo_usdt_antesZ
item_vendart   r   Zvalor_excessoZquantidade_vendar"  r#  r)  r`   r   r*  r+  Zsaldo_usdt_atualZcompras_planejadasZtotal_usdt_necessarioZitem_comprar!  Zfator_reducaor  r5  Zquantidade_comprar$  r%  r&  r'  r(  Zvalor_portfolio_finalZpercentuais_finaisr   r   r   fase_balanceamento_portfolioa  sR  &







	$


 


 




	$
2
r8  c               
   C   s  zt t} | rt| tstd W dS dd tD }t|}dd |D }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 ]@}||d}||d}	|	r||	 nd}
||d}| di |d}t
| d|dd d!|
d"d |d#d$|dd%  qt
d& | W S  ty } 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   rv   r   r   r   r   r   a  r   z'relatorio_portfolio.<locals>.<listcomp>c                 S   r  r  r  r   r   r   r   r   c  r   z'relatorio_portfolio.<locals>.<dictcomp>G
======================================================================u   RELATÓRIO DO PORTFÓLIOF======================================================================zFase: r   Zdesconhecidau   Data de Início: r   r   r   r)   r   r   zValor Atual: r@   zGanho/Perda: r.  z	Ganho %: rU   r.   r/  zF----------------------------------------------------------------------r   z: Saldo=z15.8fz | zValor: z12.2fz6.2fr-  r   zG======================================================================
u   Erro ao exibir relatório: )r&   r   
isinstancedictrN   r   rl   ru   rx   r   rJ   r\   upperrh   r#   rL   r   	print_exc)r   ri   rj   rq   r  rw   Zcapitalrk   saldort   r  Zpctr7  r%   r   r   r   relatorio_portfolioY  sP   
r@  c               
   C   sN  t d t d t d t \} }d}d}zc	 |d7 }|d7 }z3| d dkr,t| |} n| d d	kr7t| |} |tkrDt }|rB|} d}t d
t d tt W n% t	yw } 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 principalr9  u/   ROBÔ DE BALANCEAMENTO DE PORTFÓLIO - INICIADOr:  r   TrU   r   r   r   u   
Próximo ciclo em z segundos...zErro no ciclo r   Nu!   
Robô interrompido pelo usuáriozErro fatal: )rJ   r   r,  r8  TEMPO_REFRESHr@  TEMPO_CICLOr7   r_   r#   rL   r   r>  KeyboardInterrupt)r   ri   Zcontador_cicloZcontador_relatorioZestado_atualizador%   r   r   r   main  sJ   

rD  __main__)N)g__doc__r4   ZpandasZpdr7   r   Zlogging.handlersr   r   localer   r   r   r   pytzZcoloramar   r   r   r   r   r&   	setlocaleLC_ALLErrorconfigr\   ZAPI_KEYZ
API_SECRETZAPI_KEY_TESTNETZAPI_SECRET_TESTNETZTESTNETrh   r]   r   r6   rB  rA  Z	TIMEFRAMEr6  r   r  r   r  r  r   ZLOG_FILENAMEr   	getLoggerloggersetLevelINFOhandlershandlerremoveHandlerZrotating_handler	Formatter	formattersetFormatter
addHandlerrD   r=   r<   Z	chave_apiZchave_secretar5   rZ   Zset_sandbox_moderF   r9   Zload_marketsrO   r;   r#   r%   r"   rJ   rL   rN   rP   re   rg   rl   rp   ru   rx   r   r   r   r   r   r   r   r   r   r   r   r   r,  r8  r@  rD  __name__r   r   r   r   <module>   s  












' Pe#$
!<6 0 y5
*
