o
    fim                     @   s   d Z ddlZddlmZ ddlmZmZmZ ddlmZ	 ddl
mZ ddlmZ dd	lmZ dd
lmZ eeZG dd dZdS )u.  
风控熔断器

实时风控检查，在下单前和持仓期间执行:
1. 单日亏损 > 5% → 暂停交易
2. 总回撤 > 25% → 全部平仓
3. 保证金不足 → 拒绝开仓
4. 单币仓位超限 → 拒绝开仓
5. 总仓位超限 → 拒绝开仓

所有熔断事件都推送Telegram告警
    N)Optional)datetimetimezonedate   )settings)get_coin)calc_effective_equity)Database)TelegramNotifierc                   @   s   e Zd ZdZdedefddZdd Zdd	 Ze	d
e
fddZ		d"dededededed
efddZdedefddZdedefddZdd Zdefdd Zd!S )#	RiskGuardu  
    风控熔断器

    用法:
        guard = RiskGuard(db, notifier)

        # 开仓前检查
        ok, reason = guard.pre_trade_check(
            balance=10000, margin_needed=2000,
            symbol='BTCUSDT', used_margin=3000
        )

        # 交易后更新
        guard.record_trade_result(pnl=-200, balance=9800)

        # 检查是否可交易
        if guard.is_halted:
            print("交易已暂停")
    dbnotifierc                 C   s6   || _ || _d| _d | _d| _d| _d| _|   d S )N        F )r   r   	daily_pnlcurrent_datepeak_balancehaltedhalt_reason_restore_state)selfr   r    r   (/opt/langlang_ai/execution/risk_guard.py__init__0   s   zRiskGuard.__init__c                 C   sZ   t | jdd| _| jdddk| _| jdd| _| jr+td| j d d	S d	S )
u   从数据库恢复r   0risk_halted1r   r   zRisk guard: HALTED ()N)floatr   	get_stater   r   r   loggerwarningr   r   r   r   r   =   s   zRiskGuard._restore_statec                 C   s@   | j dt| j | j d| jrdnd | j d| j dS )u   保存状态r   r   r   r   r   N)r   	set_statestrr   r   r   r#   r   r   r   _save_stateF   s   zRiskGuard._save_statereturnc                 C   sZ   t tj }| j|kr*|| _d| _| jr*| jdkr*d| _d| _| 	  t
d | jS )u   是否处于熔断状态r   
daily_lossFr   z"Daily loss halt released (new day))r   nowr   utcr   r   r   r   r   r&   r!   info)r   todayr   r   r   	is_haltedL   s   

zRiskGuard.is_haltedr   balancemargin_neededsymbolused_marginmonth_start_balancec           	      C   s   | j rdd| j fS |dkrdS ||kr!dd|dd|dfS |dkr3t||}||tj kr3dS ||tj krCdd	tjd
fS || }||tj krWddtjd
fS | jdkrt| j| | j }|tjd krtt	d|d dS )ua   
        开仓前风控检查

        Returns:
            (passed: bool, reason: str)
        Fu   熔断中: r   )Fu	   余额<=0u
   保证金$,.0fu
    > 余额$   超过有效权益单币上限u   单币仓位超过.0%u   总仓位超过g?zApproaching drawdown limit: .1%)Tu   通过N)Fr4   )
r-   r   r	   SSINGLE_COIN_LIMITTOTAL_POSITION_LIMITr   TOTAL_DD_HALTr!   r"   )	r   r.   r/   r0   r1   r2   	effectivetotal_marginddr   r   r   pre_trade_check^   s(   

zRiskGuard.pre_trade_checkpnlc                 C   s   t | j|| _ttj }| j|kr|| _d| _|  j|7  _|dkr@| j| t	j
 k r@| dd| j| ddt	j
d | jdkra| j| | j }|t	jkra| dd	|ddt	jd |   d
S )u   
        记录交易结果，检查是否触发熔断

        Args:
            pnl: 本笔盈亏
            balance: 当前余额
        r   r   r(   u   单日亏损r6   z > r5   total_drawdownu	   总回撤N)maxr   r   r)   r   r*   r   r   r   r7   DAILY_LOSS_HALT_trigger_haltr:   r&   )r   r?   r.   r,   r=   r   r   r   record_trade_result   s"   	


zRiskGuard.record_trade_resultreasonmessagec                 C   sL   d| _ || _|   td|  | jd| d|dkrdnd  dS )	u   触发熔断TzRISK HALT: u   🚨 风控熔断!
原因: u   
所有新开仓已暂停
r(   u   日亏熔断次日自动解除u   需手动解除N)r   r   r&   r!   criticalr   	send_sync)r   rE   rF   r   r   r   rC      s   zRiskGuard._trigger_haltc                 C   s.   d| _ d| _|   td | jd dS )u   手动解除熔断Fr   zRisk halt manually releasedu   ✅ 风控熔断已手动解除N)r   r   r&   r!   r+   r   rH   r#   r   r   r   manual_resume   s
   
zRiskGuard.manual_resumenew_peakc                 C   s$   || _ |   td|d dS )u   重置峰值余额（慎用）zPeak balance reset to $r3   N)r   r&   r!   r+   )r   rJ   r   r   r   
reset_peak   s   zRiskGuard.reset_peakN)r   r   )__name__
__module____qualname____doc__r
   r   r   r   r&   propertyboolr-   r   r%   tupler>   rD   rC   rI   rK   r   r   r   r   r      s4    	
3!r   )rO   loggingtypingr   r   r   r   configr   r7   config.coinsr   core.positionr	   data.databaser
   notify.telegram_botr   	getLoggerrL   r!   r   r   r   r   r   <module>   s    
