o
    @šjz  ã                	   @   sò   d Z ddlZddlmZ ddlmZ ddlmZ edƒZ	de
de
fd	d
„Zdede
de
fdd„Zd$de
dede
fdd„Zd$de
dede
fdd„Zd$de
de
dede
fdd„Zde
de
de
defdd„Zde
de
defdd „Zd!edefd"d#„ZdS )%u§  
risk_manager.py

Two responsibilities:
1. Position sizing (how many shares, given account equity and risk %)
2. Stop calculation â€” initial stop and the dynamic trailing stop that
   only ever moves up (never back down), per the project's explicit
   spec and worked examples.

Supports four configurable stop methods: fixed_cents, percentage, atr,
volatility_adjusted. The method is chosen entirely through config.json.
é    N©Ú
get_config)Ú
get_logger)ÚatrÚrisk_managerÚxÚreturnc                 C   s   t | d dƒS )Ng•Ö&è.>é   )Úround)r   © r   úH/var/www/screener/trade/premarket_backup_2026-09-08_2010/risk_manager.pyÚ_round_to_cent   s   r   ÚcfgÚpricec                 C   s   t | d ||  dd¡d  ƒS )a  
    [FEATURE 2026-09-03] min_stop_distance_cents alone is a flat dollar
    floor -- fine at one price level, negligible at another. Several
    real 2026-09-03 entries (ACHR, CRML, HAFN, JOBY) landed exactly on
    or barely above that $0.03 floor because the ATR-derived distance
    was tiny at entry time, leaving only $0.03-$0.05 (0.4-0.7% of price)
    of actual room -- not enough to survive ordinary 1-minute noise on
    this project's $5-15 cohort. Takes the larger of the flat-cents
    floor and min_stop_distance_pct% of the current price, so the
    percentage floor is what actually governs at this project's normal
    price range while min_stop_distance_cents remains a floor-of-the-
    floor for any very low-priced name where 1% would be a fraction of
    a cent.
    Úmin_stop_distance_centsÚmin_stop_distance_pctr   ç      Y@)ÚmaxÚget)r   r   r   r   r   Ú_min_stop_distance   s   r   Úcurrent_priceÚbarsc           
      C   s  t ƒ d }|d }|dkr|d }nd|dkr| |d d  }nW|dkr>|s/t d	¡ |d }nGt||d
 d�}||d  }n8|dkri| |d d  }|rft||d
 d�}||d  }|dkrct||ƒn|}n|}nt d|› d�¡ |d }t|| ƒ}| |d d  }	t|t||	ƒƒ}t|ƒS )z±
    Returns the trailing distance in dollars, based on the configured
    method. `bars` (recent 1-min bars) is required for atr/volatility
    methods; ignored otherwise.
    ÚstopÚmethodÚfixed_centsÚtrailing_distanceÚ
percentageÚpercentage_trailing_pctr   r   zKatr stop method requested but no bars supplied; falling back to fixed_centsÚ
atr_period©ÚperiodÚatr_multiplier_trailingÚvolatility_adjustedr   zUnknown stop method 'z', defaulting to fixed_centsÚmax_stop_distance_pct)r   ÚlogÚwarningÚcalc_atrÚminr   r   r   )
r   r   r   r   ÚdistanceÚaÚpct_distanceÚatr_distanceÚmin_distÚmax_distr   r   r   Úcompute_stop_distance,   s2   




r.   Úentry_pricec                 C   s
  t ƒ d }|d }|dkr|d }nV|dkr| |d d  }nI|dkr<|r-t||d	 d
�nd}|r7||d  n|d }n,|dkrd| |d d  }|rRt||d	 d
�nd}|r\||d  n|}t||ƒ}n|d }t|| ƒ}| |d d  }	t|t||	ƒƒ}t| | ƒ}
|
S )Nr   r   r   Úinitial_distancer   Úpercentage_initial_pctr   r   r   r   r   Úatr_multiplier_initialr"   r#   )r   r&   r'   r   r   r   )r/   r   r   r   r(   r)   r*   r+   r,   r-   r   r   r   r   Úcompute_initial_stopZ   s(   


r3   Úhighest_priceÚcurrent_stopc                 C   s&   t | |ƒ}t| | ƒ}||kr|S |S )z­
    Core trailing-stop rule from the spec:
        new_stop = highest_price - trailing_distance
        only update if new_stop > current_stop  (stop NEVER moves down)
    )r.   r   )r4   r5   r   r(   Úcandidate_stopr   r   r   Úupdate_trailing_stopt   s
   
r7   Úaccount_equityÚinitial_stopc                 C   s–   t ƒ d }t ƒ d }| |d d  }t|| dƒ}t || ¡}| |d d  }|dkr3t || ¡nd}	t||	ƒ}
t|
|
dkrD|d ndƒ}
t|
ƒS )	zé
    Risk-based sizing: risk `account_risk_pct_per_trade`% of equity on
    the distance between entry and initial stop, capped by a maximum
    notional percentage of equity to avoid oversized positions on
    very tight stops.
    ÚriskÚtradingÚaccount_risk_pct_per_trader   g{®Gáz„?Ú#max_position_notional_pct_of_equityr   Ú
min_shares)r   r   ÚmathÚfloorr'   Úint)r8   r/   r9   r   Útrading_cfgÚrisk_dollarsÚper_share_riskÚshares_by_riskÚmax_notionalÚshares_by_notionalÚsharesr   r   r   Úcompute_position_size�   s   


rI   Úrealized_pl_todayc                 C   s$   t ƒ d }| |d d  }| |kS )zJReturns True if the daily loss limit has been breached (halt new entries).r:   Úmax_daily_loss_pctr   r   )rJ   r8   r   Úmax_lossr   r   r   Úcheck_daily_loss_limit—   s   
rM   Úrecent_trade_resultsc                 C   sB   t ƒ d }|d }t| ƒ|k rdS | | d… }tdd„ |D ƒƒS )z”
    recent_trade_results: chronological list of booleans, True = win.
    Returns True if bot should pause new entries due to a losing streak.
    r:   Úmax_consecutive_losses_pauseFNc                 s   s   � | ]}|d u V  qdS )FNr   )Ú.0Úresultr   r   r   Ú	<genexpr>¨   s   € z/check_consecutive_loss_pause.<locals>.<genexpr>)r   ÚlenÚall)rN   r   ÚlimitÚtailr   r   r   Úcheck_consecutive_loss_pausež   s   
rW   )N)Ú__doc__r?   Úconfig_loaderr   Úlogger_setupr   Ú
indicatorsr   r&   r$   Úfloatr   Údictr   Úlistr.   r3   r7   rA   rI   ÚboolrM   rW   r   r   r   r   Ú<module>   s    .