
    ݡi!                    V    d Z ddlmZ ddlmZ ddlZddlZddZ	e G d d             Z
y)	a  
Daily swing mean-reversion engine based on Connors RSI (CRSI) pullbacks.

This implementation uses a standard RSI calculation via:
  * price.diff()
  * positive/negative clipping
  * Wilder-style smoothing via pandas .ewm(...)

No external TA libraries required.
    )annotations)	dataclassNc                   |dk  rt        d      | j                  t        j                        }|j	                         }|j                  d      }| j                  d      }dt        |      z  }|j                  |d|      j                         }|j                  |d|      j                         }||j                  dt        j                        z  }	ddd|	z   z  z
  }
|
S )	a2  
    Compute the standard RSI using Wilder-style exponentially smoothed averages.

    RSI = 100 - 100 / (1 + RS)
    RS = AvgGain / AvgLoss

    Parameters
    ----------
    close
        Price series (DatetimeIndex recommended).
    window
        Lookback period for smoothing (e.g. 2-period RSI).
    r   zwindow must be > 0        )lower      ?F)alphaadjustmin_periodsg      Y@)
ValueErrorastypenpfloat64diffclipfloatewmmeanreplacenan)closewindowcdeltagainlossr	   avg_gainavg_lossrsrsis              ?/opt/rentech/trading_bot/RenTech/strategy_stack/swing_engine.py
rsi_wilderr"      s     {-..RZZ AFFHE::C: DF==s=#D%-ExxeEvxFKKMHxxeEvxFKKMH	H$$S"&&1	1B
5C"H%
&CJ    c                  R    e Zd ZU dZdZded<   dZded<   dZded	<   d
Zded<   ddZ	y)SwingEnginea?  
    Connors RSI-like pullback strategy on daily bars.

    Entry (vectorized state machine):
      * close > SMA(trend_sma)
      * RSI(rsi_window) < rsi_threshold

    Exit:
      * close > SMA(exit_sma)

    The engine outputs:
      * `micro_position`: {-1,0,1} positions (0/1 for this long-only CRSI pullback)
       int	trend_sma   
rsi_windowg      $@r   rsi_threshold   exit_smac           	     F   |j                   rt        d      d|j                  vrt        d      |j	                         j                         }|d   j                  t        j                        }|d   j                  | j                  | j                        j                         }|d   j                  | j                  | j                        j                         }t        || j                        }||d<   ||d<   ||d<   ||d   kD  |d   t        | j                         k  z  }||d   kD  }||d<   ||d	<   t        j"                  |j%                         d
t        j"                  |j%                         dt        j&                              }	t)        j*                  |	|j,                  t        j                        }	|	j/                         j1                  d      }	|	j3                  d      j1                  d      j                  t        j4                        |d<   |S )z
        Transform daily OHLCV into signal + position columns.

        Expected columns
        -----------------
        daily
            Must contain `close` column.
        zdaily is emptyr   z#daily must contain a 'close' column)r   r   sma_200sma_5rsi_2entry_signalexit_signalr   r   )indexdtype   micro_position)emptyr   columnsKeyError
sort_indexcopyr   r   r   rollingr(   r   r-   r"   r*   r   r+   whereto_numpyr   pdSeriesr4   ffillfillnashiftint8)
selfdailydfr   	sma_trendsma_exitr    r2   r3   target_positions
             r!   	transformzSwingEngine.transformG   s    ;;-..%--'@AA$$&7""2::.wK''t~~4>>'Z__a	g;&&dmm&W\\^0!977 9-"W+dFXFX@Y2YZbk))>'= ((<#8#8#:C+J^J^J`begigmgmAno))O2882::V)//188=  /44Q7>>sCJJ277S	r#   N)rG   pd.DataFramereturnrM   )
__name__
__module____qualname____doc__r(   __annotations__r*   r+   r-   rL    r#   r!   r%   r%   2   s6     IsJM5Hc'r#   r%   )r   	pd.Seriesr   r'   rN   rU   )rR   
__future__r   dataclassesr   numpyr   pandasr@   r"   r%   rT   r#   r!   <module>rZ      s6   	 # !  < ; ; ;r#   